web-dev-qa-db-ja.com

ファイルにデータを追加すると、curl / wgetが^ Mを追加します

何かがこれについて私を騒がせています。 2つの異なるhostsファイルを1つにダウンロードしようとしています。これを個別に実行すると、すべて問題ありませんが、2番目にファーを追加すると奇妙な文字^MはHostファイルの各行に表示されます。

ここで実際の例を示すために私がしていること

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

/etc/hostsこれらを持っている: enter image description here

しかし、私がこれを別々に行うとき、そう

curl -s "https://raw.githubusercontent.com/CHEF-KOCH/CKs-FilterList/master/HOSTS/CK's-Spotify-HOSTS-FilterList.txt" > /tmp/hosts

/tmp/hostsは完全に正常です

enter image description here

なんでこんなことが起こっているの?ファイルを個別にダウンロードすると、間違った改行が表示されないのに、それらを組み合わせると表示されるのはなぜですか。 0x0a0x0dではなく0x0aであるはずですが、なぜこれが発生するのですか?

ダウンロードされているファイルを確認する必要がある場合は、コマンドのリンクにアクセスできます。

  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

編集: 2番目のHost ファイルのみをダムホストファイルに追加しようとしましたが、同じことが起こったので、最初のファイルが問題の原因であることを省略できます

1
AK_

何も追加しているツールはありません。いくつかの理由のために、それはかなり混乱しています(しかしあなたのせいではありません)。

2つの一般的な行末があります。

  • Unixスタイル、LF(または_\n_または_0x0a_)で示される1文字、
  • Windowsスタイル、2文字、CRLF(または_\r\n_または_0x0d 0x0a_)。

2つの異なるURLからダウンロードします。サーバーは各ファイルが_text/plain_であると主張しているようですので、 CRLF を使用する必要があります。 2番目のもの(あなたがcurl)は実際にCRLFを使用しますが、最初のもの(あなたがwget)は代わりに唯一のLFを違法に使用します。

最初のURLからのみダウンロードして(wgetまたはcurlのどちらを使用するかに関係なく)、結果を_hosts1_ファイルに保存すると、_file hosts1_は次のようになります。

_hosts1: UTF-8 Unicode text
_

(これは、行末がLFであることを意味します。そうでない場合は、_UTF-8 Unicode text, with CRLF line terminators_になります)。

2番目のURLからのみダウンロードし、結果を_hosts2_ファイルに保存すると、_file hosts2_は次のようになります。

_hosts2: ASCII text, with CRLF line terminators
_

両方を同じファイル(たとえば_hosts12_)にダウンロードする場合、最初のURLからの行の行末としてLFを取得し、としてCRLFを取得します。 2番目のURLからの行の行末。

実際には、ファイルがLFまたはCRLFのどちらを使用しているかを判断しようとするツールは、すべてではなく、多くても数行の最初の行を調べます。 _file hosts12_を試してみると、次のようになります。

_hosts12: UTF-8 Unicode text
_

_hosts1_の場合とまったく同じです。 _vim hosts12_の場合も同じことが起こります。エディターは、ファイルの先頭に基づいて行末をLFとして検出します。次に、最後までスキップすると、CR文字を表す多くの_^M_-が表示されます。 vimは、この場合、CRが適切な行末の一部であるとは見なさないため、それらを出力します。

ただし、_vim hosts2_を実行すると、エディターは行末をCRLFとして正しく検出します。以前に_^M_として出力されたのと同じCR文字は、vimが適切な行末の一部であると見なすため、現在は非表示になっています。手動で改行を追加した場合、Unixを使用している場合でも、vimはWindowsスタイルの行末を使用します。このファイルは「完全に正常」だと思われるかもしれませんが、通常のUnixテキストファイルではありません。

混乱は、サーバー上の2つのファイルが異なる行末を使用しているためです。次に、vimは賢くしようとします。

Linux(一般的にはUnix)では、_/etc/hosts_で行末としてLFを使用する必要があります。 line および newline character のPOSIX定義を参照してください。文字が_\n_であることが明示されています:

3.243改行文字(_<newline>_)
出力ストリームで、印刷を次の行の先頭から開始する必要があることを示す文字。これは、C言語で_'\n'_で指定された文字です。

その場合、ツールは_\r\n_をサポートする義務はないと思います。簡単な解決策は、_wget … && curl … >> …_を実行したとおりに実行してから、_dos2unix /etc/hosts_を呼び出すことです。

もし私があなたなら、別のファイル、たとえば_/etc/hosts.tmp_で作業します。 wgetcurl、_dos2unix_、_chmod --reference=/etc/hosts_、_chown --reference=/etc/hosts_を使用します。ファイルが完成したときのみ、mvを_/etc/hosts_に置き換えます。 rename(2) のこの機能は関連しています:

newpathがすでに存在する場合、それはアトミックに置き換えられるため、newpathにアクセスしようとしている別のプロセスがそれを見つけられないことはありません。

したがって、どのプロセスでも、古い_/etc/hosts_(mvの前)または新しい__(mvの後)のいずれかが見つかります。 _/etc/hosts_を直接操作する現在のアプローチでは、別のプロセスがファイルの不完全性や行末の終わり近くで間違った行末を検出した場合のシナリオが可能です。

3