Kein Werkzeug fügt etwas hinzu. Es ist ziemlich verwirrend (aber nicht Ihre Schuld überhaupt) aus wenigen Gründen.
Es gibt zwei gemeinsame Leitungsenden:
- Unix-Stil, ein Zeichen
LF
(oder\n
oder0x0a
), - Windows-Stil, zwei Zeichen
CRLF
(oder\r\n
oder0x0d 0x0a
).
Sie können von zwei verschiedenen URLs herunterladen. Es scheint, die Server Ansprüche jede Datei ist text/plain
, so sollten sie nutzenCRLF
. Die zweite (die, die Sie verwenden curl
) verwendet zwar tatsächlich CRLF
, aber die erste (die, die Sie verwenden wget
) verwendet illegal die Sohle LF
.
Wenn Sie nur von der ersten URL herunterladen (egal ob mit wget
oder curl
) und das Ergebnis in einer hosts1
Datei speichern, erhalten Sie file hosts1
Folgendes:
hosts1: UTF-8 Unicode text
(Dies bedeutet, dass die Zeilenenden sind LF
, sonst wäre das der Fall UTF-8 Unicode text, with CRLF line terminators
).
Wenn Sie nur von der zweiten URL herunterladen und das Ergebnis in einer hosts2
Datei speichern, erhalten Sie file hosts2
Folgendes:
hosts2: ASCII text, with CRLF line terminators
Wenn Sie auf dieselbe hosts12
Art und Weise (z. B. ) beide Dateien herunterladen, erhalten Sie LF
als Zeilenende für Zeilen, die von der ersten URL stammen, und CRLF
als Zeilenende für Zeilen, die von der zweiten URL stammen.
In der Praxis jedes Werkzeug, das versucht zu ermitteln, ob eine Datei höchstens einige Anfangszeilen verwendet LF
oder CRLF
untersucht, nicht alle. Versuchen Sie file hosts12
und Sie erhalten:
hosts12: UTF-8 Unicode text
genau so wie es war hosts1
. Das Gleiche passiert, wenn Sie vim hosts12
: Der Editor erkennt Zeilenenden LF
anhand des Dateianfangs. Dann überspringen Sie bis zum Ende und sehen viele ^M
-s, die CR
Zeichen kennzeichnen. vim
druckt sie, weil sie CR
in diesem Fall nicht als Teil der richtigen Zeilenenden betrachtet wird.
Wenn Sie jedoch erkennen vim hosts2
, erkennt der Editor die Zeilenenden korrekt als CRLF
. Die gleichen CR
Zeichen, die wie ^M
zuvor gedruckt wurden, sind jetzt für Sie ausgeblendet, da vim
sie als Teil der richtigen Zeilenenden betrachtet werden. Wenn Sie eine neue Zeile von Hand hinzugefügt haben, vim
würde die Endung im Windows-Stil verwendet, auch wenn Sie mit Unix arbeiten. Sie denken vielleicht, dass die Datei "völlig normal" ist, aber es ist keine normale Unix-Textdatei.
Die Verwirrung besteht darin, dass die beiden Dateien auf dem Server unterschiedliche Zeilenenden verwenden. dann vim
versucht, klug zu sein.
In Linux (Unix im Allgemeinen) Sie mögen, dass Ihre /etc/hosts
verwenden LF
als Zeilenende. Siehe POSIX-Definitionen für Zeilen- und Zeilenvorschubzeichen . Es wird ausdrücklich gesagt, dass der Charakter ist \n
:
3.243 Newline Character (
<newline>
)
Ein Zeichen, das im Ausgabestrom anzeigt, dass der Druck am Anfang der nächsten Zeile beginnen soll. Es ist das Zeichen, das'\n'
in der Sprache C angegeben ist.
Ich glaube nicht, dass Werkzeuge zur Unterstützung verpflichtet sind \r\n
. Die einfache Lösung besteht darin, wget … && curl … >> …
genau so zu laufen, wie Sie es getan haben, und dann aufzurufen dos2unix /etc/hosts
.
Wenn ich Sie wäre, würde ich mit einer anderen Datei arbeiten /etc/hosts.tmp
. Ich würde verwenden wget
, curl
, dos2unix
, chmod --reference=/etc/hosts
, chown --reference=/etc/hosts
. Erst wenn die Datei vollständig ist, würde ich mv
sie ersetzen /etc/hosts
. Diese Funktion von rename(2)
ist relevant:
Wenn es
newpath
bereits existiert, wird es atomar ersetzt, sodass es keinen Zeitpunkt gibt, an dem ein anderer Prozess, der versucht, auf den Zugriff zuzugreifennewpath
, es als fehlend erkennt.
Jeder Prozess würde also entweder den alten /etc/hosts
(vor mv
) oder den neuen (nach mv
) finden. Ihr aktueller Ansatz, direkt mit zu arbeiten, /etc/hosts
ermöglicht Szenarien, in denen ein anderer Prozess die Datei als unvollständig oder mit falschen Zeilenenden am Ende findet.