何かがこれについて私を騒がせています。 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
しかし、私がこれを別々に行うとき、そう
curl -s "https://raw.githubusercontent.com/CHEF-KOCH/CKs-FilterList/master/HOSTS/CK's-Spotify-HOSTS-FilterList.txt" > /tmp/hosts
今/tmp/hosts
は完全に正常です
なんでこんなことが起こっているの?ファイルを個別にダウンロードすると、間違った改行が表示されないのに、それらを組み合わせると表示されるのはなぜですか。 0x0a0x0dではなく0x0aであるはずですが、なぜこれが発生するのですか?
ダウンロードされているファイルを確認する必要がある場合は、コマンドのリンクにアクセスできます。
編集: 2番目のHost ファイルのみをダムホストファイルに追加しようとしましたが、同じことが起こったので、最初のファイルが問題の原因であることを省略できます
何も追加しているツールはありません。いくつかの理由のために、それはかなり混乱しています(しかしあなたのせいではありません)。
2つの一般的な行末があります。
LF
(または_\n
_または_0x0a
_)で示される1文字、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
_で作業します。 wget
、curl
、_dos2unix
_、_chmod --reference=/etc/hosts
_、_chown --reference=/etc/hosts
_を使用します。ファイルが完成したときのみ、mv
を_/etc/hosts
_に置き換えます。 rename(2)
のこの機能は関連しています:
newpath
がすでに存在する場合、それはアトミックに置き換えられるため、newpath
にアクセスしようとしている別のプロセスがそれを見つけられないことはありません。
したがって、どのプロセスでも、古い_/etc/hosts
_(mv
の前)または新しい__(mv
の後)のいずれかが見つかります。 _/etc/hosts
_を直接操作する現在のアプローチでは、別のプロセスがファイルの不完全性や行末の終わり近くで間違った行末を検出した場合のシナリオが可能です。