curl / wget fügt ein zusätzliches ^ M hinzu, wenn ich Daten an eine Datei anhange

478
AK_

Etwas bringt mich dazu. Ich versuche, zwei verschiedene Host-Dateien in eine zu laden. Wenn ich dies seriell mache, ist alles in Ordnung, aber wenn ich die firs an die zweite anhange, ^Merscheint in jeder Zeile der Host-Datei ein seltsamer Charakter .

Um hier ein echtes Beispiel zu geben, was ich tue

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 

jetzt /etc/hostshaben diese: curl / wget fügt ein zusätzliches ^ M hinzu, wenn ich Daten an eine Datei anhange

aber wenn ich das getrennt mache, so

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

jetzt /tmp/hostsist völlig normal

curl / wget fügt ein zusätzliches ^ M hinzu, wenn ich Daten an eine Datei anhange

Warum passiert dies? Wenn ich die Dateien separat herunterlade, bekomme ich nicht den falschen Zeilenvorschub, aber wenn ich sie kombiniere, bekomme ich sie. Es soll 0x0a sein und nicht 0x0a0x0d. Warum passiert das?

Wenn Sie sich die heruntergeladenen Dateien ansehen möchten, können Sie die Links in den Befehlen aufrufen:

  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

BEARBEITEN: Ich habe versucht, nur die zweite Host- Datei an eine dumme Hosts-Datei anzuhängen, und es ist dasselbe passiert. Wir können also weglassen, dass die erste Datei die Ursache des Problems ist

1
"Es soll 0x0a sein, nicht 0x0a0x0d" - Ich denke, Sie erhalten `0x0d 0x0a`, nicht umgekehrt. Oder ist es wirklich 0x0a 0x0d? Kamil Maciorowski vor 5 Jahren 0
@ KamilMaciorowski Was auch immer "^ M" auf VIM ist. AK_ vor 5 Jahren 0

1 Antwort auf die Frage

3
Kamil Maciorowski

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 \noder 0x0a),
  • Windows-Stil, zwei Zeichen CRLF(oder \r\noder 0x0d 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 wgetoder curl) und das Ergebnis in einer hosts1Datei speichern, erhalten Sie file hosts1Folgendes:

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 hosts2Datei speichern, erhalten Sie file hosts2Folgendes:

hosts2: ASCII text, with CRLF line terminators 

Wenn Sie auf dieselbe hosts12Art und Weise (z. B. ) beide Dateien herunterladen, erhalten Sie LFals Zeilenende für Zeilen, die von der ersten URL stammen, und CRLFals 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 LFoder CRLFuntersucht, nicht alle. Versuchen Sie file hosts12und Sie erhalten:

hosts12: UTF-8 Unicode text 

genau so wie es war hosts1. Das Gleiche passiert, wenn Sie vim hosts12: Der Editor erkennt Zeilenenden LFanhand des Dateianfangs. Dann überspringen Sie bis zum Ende und sehen viele ^M-s, die CRZeichen kennzeichnen. vimdruckt sie, weil sie CRin 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 CRZeichen, die wie ^Mzuvor gedruckt wurden, sind jetzt für Sie ausgeblendet, da vimsie als Teil der richtigen Zeilenenden betrachtet werden. Wenn Sie eine neue Zeile von Hand hinzugefügt haben, vimwü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 vimversucht, klug zu sein.

In Linux (Unix im Allgemeinen) Sie mögen, dass Ihre /etc/hostsverwenden LFals 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 mvsie ersetzen /etc/hosts. Diese Funktion von rename(2)ist relevant:

Wenn es newpathbereits existiert, wird es atomar ersetzt, sodass es keinen Zeitpunkt gibt, an dem ein anderer Prozess, der versucht, auf den Zugriff zuzugreifen newpath, 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/hostsermöglicht Szenarien, in denen ein anderer Prozess die Datei als unvollständig oder mit falschen Zeilenenden am Ende findet.

erstaunlich erklärt, danke! Wird es weh tun, wenn ich die Dinge so halte, wie sie sind? (Wird die Hostdatei ohnehin `CRLF 'als korrekte Zeilenende erkennen?) AK_ vor 5 Jahren 0
@AK_ Ich denke, es gibt kein Konzept wie "Datei, die CRLF erkennt", sondern "Werkzeuge, die CRLF erkennen". In meinem Kubuntu stört es zumindest * einigen * nicht, dass gemischte Zeilen enden. Im Allgemeinen würde ich nicht darauf zählen. Siehe POSIX-Definitionen von [line] (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206) und [Zeilenvorschubzeichen] (http://pubs.opengroup.org/onlinepubs/9699919799/ basedefs / V1_chap03.html # tag_03_243). Es wird ausdrücklich angegeben, dass das Zeichen "\ n" ist. Ich glaube nicht, dass Werkzeuge dazu verpflichtet sind, `\ r \ n` dann zu unterstützen. Kamil Maciorowski vor 5 Jahren 0