当我将数据附加到文件时,curl / wget 添加额外的 ^M

AK_*_*AK_ 2 linux download wget curl special-characters

这件事让我心烦意乱。我正在尝试将两个不同的主机文件下载到一个文件中,如果我依次执行此操作,那么一切都很好,但是当我将第一个文件附加到第二个文件时,^M主机文件的每一行都会出现一个奇怪的字符。

在这里举一个真实的例子我正在做什么

wget https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts -O /etc/hosts && curl -s "https://raw.githubusercontent.com/CHEF-KOCH/CKs-FilterList/master/HOSTS/CK's-Spotify-HOSTS-FilterList.txt" >> /etc/hosts
Run Code Online (Sandbox Code Playgroud)

现在/etc/hosts有这些: 在此输入图像描述

但是当我单独这样做时,所以

curl -s "https://raw.githubusercontent.com/CHEF-KOCH/CKs-FilterList/master/HOSTS/CK's-Spotify-HOSTS-FilterList.txt" > /tmp/hosts
Run Code Online (Sandbox Code Playgroud)

现在/tmp/hosts完全正常

在此输入图像描述

为什么会发生这种情况?为什么当我单独下载文件时,我没有得到错误的换行符,但当我将它们合并时,却得到了错误的换行符。它应该是0x0a而不是0x0a0x0d,为什么会发生这种情况?

如果您需要查看正在下载的文件,可以访问命令中的链接:

  1. https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
  2. https://raw.githubusercontent.com/CHEF-KOCH/CKs-FilterList/master/HOSTS/CK%27s-Spotify-HOSTS-FilterList.txt

编辑:我尝试仅将第二个主机文件附加到哑主机文件中,并且发生了同样的情况,因此我们可以忽略第一个文件是问题的原因

Kam*_*ski 7

没有工具可以添加任何东西。由于几个原因,这是相当混乱的(但根本不是你的错)。

\n\n

有两种常见的行结尾:

\n\n
    \n
  • Unix 风格,一个字符表示LF(或\\n0x0a),
  • \n
  • Windows 风格,两个字符,CRLF(或\\r\\n0x0d 0x0a)。
  • \n
\n\n

您从两个不同的 URL 下载。看来服务器声称每个文件都是text/plain,所以他们应该使用CRLF. 第二个(您的curl)确实使用了CRLF,但第一个(您的wget)非法地使用了 sole LF

\n\n

如果您仅从第一个 URL 下载(无论是否带有wgetcurl)并将结果存储在hosts1文件中,则将file hosts1产生:

\n\n
hosts1: UTF-8 Unicode text\n
Run Code Online (Sandbox Code Playgroud)\n\n

(这意味着行结尾是LF,否则就是UTF-8 Unicode text, with CRLF line terminators)。

\n\n

如果您仅从第二个 URL 下载并将结果存储在hosts2文件中,则会file hosts2产生:

\n\n
hosts2: ASCII text, with CRLF line terminators\n
Run Code Online (Sandbox Code Playgroud)\n\n

hosts12如果您按照您的方式将两者下载到同一个文件(例如),您将获得LF来自第一个 URL 的行的行结尾和CRLF来自第二个 URL 的行的行结尾。

\n\n

在实践中,任何试图判断文件是否使用LFCRLF检查最多几个初始行(而不是全部)的工具。尝试file hosts12一下,你会得到:

\n\n
hosts12: UTF-8 Unicode text\n
Run Code Online (Sandbox Code Playgroud)\n\n

完全一样hosts1。当您执行以下操作时,也会发生同样的情况vim hosts12:编辑器LF根据文件开头检测行结尾。然后跳到最后,您会看到许多^M表示字符的 -s CRvim打印它们是因为在这种情况下它不被认为CR是正确行结尾的一部分。

\n\n

但是vim hosts2,当您执行此操作时,编辑器会正确地将行结尾检测为CRLF. CR之前打印的相同字符^M现在对您隐藏,因为vim它们被视为正确行结尾的一部分。如果您手动添加新行,vim即使您使用的是 Unix,也会使用 Windows 样式的行结尾。您可能认为该文件“完全正常”,但它不是正常的 Unix 文本文件。

\n\n

造成混乱的原因是服务器上的两个文件使用不同的行结尾;然后vim尝试变得聪明。

\n\n

在 Linux(一般为 Unix)中,您希望/etc/hosts将其用作LF行结尾。请参阅行换行符的 POSIX 定义。它明确指出该角色是\\n

\n\n
\n

3.243 换行符 ( <newline>)
\n 输出流中指示打印应从下一行开头开始的字符。\'\\n\'它是C语言中由 指定的字符。

\n
\n\n

我不认为工具有义务支持\\r\\n那时。wget \xe2\x80\xa6 && curl \xe2\x80\xa6 >> \xe2\x80\xa6简单的解决方案是完全按照您的方式运行,然后调用dos2unix /etc/hosts.

\n\n

如果我是你,我会使用另一个文件,比如/etc/hosts.tmp. 我会用wget,,,, .curl​ 只有当文件完成后,我才会将其替换为. 的这个特性是相关的:dos2unixchmod --reference=/etc/hostschown --reference=/etc/hostsmv/etc/hostsrename(2)

\n\n
\n

如果newpath已经存在,它将被自动替换,这样尝试访问的另一个进程就不会newpath发现它丢失了。

\n
\n\n

因此任何进程都会找到旧的/etc/hosts(之前mv)或新的(之后mv)。您当前的方法,直接使用/etc/hosts允许当另一个进程发现文件不完整或在其末尾附近有错误的行结尾时的情况。

\n