Ich gehe davon aus, dass jeder hier mit dem Sprichwort vertraut ist, dass alle Textdateien mit einem Zeilenumbruch enden sollten. Ich kenne diese "Regel" seit Jahren, habe mich aber immer gefragt - warum?
file
unix
text-files
newline
Will Robertson
quelle
quelle
Antworten:
Denn so definiert der POSIX-Standard eine Linie :
Daher werden Zeilen, die nicht mit einem Zeilenumbruchzeichen enden, nicht als tatsächliche Zeilen betrachtet. Aus diesem Grund haben einige Programme Probleme, die letzte Zeile einer Datei zu verarbeiten, wenn sie nicht beendet ist.
Diese Richtlinie bietet mindestens einen entscheidenden Vorteil bei der Arbeit an einem Terminalemulator: Alle Unix-Tools erwarten diese Konvention und arbeiten damit. Wenn Sie beispielsweise Dateien mit verketten
cat
, hat eine durch newline beendete Datei einen anderen Effekt als eine ohne:Und wie das vorherige Beispiel auch zeigt, führt eine Datei mit Zeilenumbruch bei der Anzeige der Datei in der Befehlszeile (z. B. über
more
) zu einer korrekten Anzeige. Eine nicht ordnungsgemäß terminierte Datei ist möglicherweise verstümmelt (zweite Zeile).Aus Gründen der Konsistenz ist es sehr hilfreich, diese Regel zu befolgen. Andernfalls ist beim Umgang mit den Standard-Unix-Tools zusätzliche Arbeit erforderlich.
Stellen Sie sich das anders vor: Wenn Zeilen nicht durch Zeilenumbrüche abgeschlossen werden, ist
cat
es viel schwieriger , Befehle wie nützlich zu machen: Wie erstellen Sie einen Befehl, um Dateien so zu verketten, dassb.txt
undc.txt
?Natürlich ist dies lösbar, aber Sie müssen die Verwendung
cat
komplexer gestalten (z. B. durch Hinzufügen von Positionsbefehlszeilenargumentencat a.txt --no-newline b.txt c.txt
), und jetzt steuert der Befehl anstelle jeder einzelnen Datei, wie er zusammen mit anderen Dateien eingefügt wird. Dies ist mit ziemlicher Sicherheit nicht bequem.… Oder Sie müssen ein spezielles Sentinel-Zeichen einführen, um eine Zeile zu markieren, die fortgesetzt und nicht beendet werden soll. Nun, jetzt stecken Sie in der gleichen Situation wie unter POSIX, außer invertiert (Zeilenfortsetzung statt Zeilenabschlusszeichen).
Auf nicht POSIX-kompatiblen Systemen (heutzutage meistens Windows) ist der Punkt umstritten: Dateien enden im Allgemeinen nicht mit einer neuen Zeile, und die (informelle) Definition einer Zeile kann beispielsweise " durch Zeilenumbrüche getrennter Text" sein. (Beachten Sie die Betonung). Dies ist völlig gültig. Für strukturierte Daten (z. B. Programmcode) wird das Parsen jedoch minimal komplizierter: Im Allgemeinen müssen Parser neu geschrieben werden. Wenn ein Parser ursprünglich unter Berücksichtigung der POSIX-Definition geschrieben wurde, ist es möglicherweise einfacher, den Token-Stream als den Parser zu ändern. Mit anderen Worten, fügen Sie am Ende der Eingabe ein Token mit „künstlicher Zeilenumbruch“ hinzu.
quelle
cat
auf nützliche und konsistente Weise.Jede Zeile sollte mit einem Zeilenumbruchzeichen abgeschlossen werden, einschließlich des letzten. Einige Programme haben Probleme beim Verarbeiten der letzten Zeile einer Datei, wenn diese nicht beendet ist.
GCC warnt vor ihm nicht , weil es nicht kann , die Datei verarbeiten, sondern weil es muss als Teil des Standard.
Referenz: Das GCC / GNU-Mail-Archiv .
quelle
wc -l
zählt die letzte Zeile einer Datei nicht, wenn sie nicht beendet ist. Auchcat
beitreten die letzte Zeile einer Datei mit der ersten Zeile der nächsten Datei in ein , wenn die letzte Zeile der ersten Datei nicht Newline beendet. So ziemlich jedes Programm, das nach Zeilenumbrüchen als Trennzeichen sucht, hat das Potenzial, dies durcheinander zu bringen.wc
wurde bereits erwähnt ....cat
und massenweise erwähnt wurdenwc
)?Diese Antwort ist eher ein Versuch einer technischen Antwort als eine Meinung.
Wenn wir POSIX-Puristen sein wollen, definieren wir eine Linie als:
Quelle: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206
Eine unvollständige Zeile als:
Quelle: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195
Eine Textdatei als:
Quelle: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397
Eine Zeichenfolge als:
Quelle: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396
Daraus können wir ableiten, dass wir möglicherweise nur dann auf Probleme stoßen, wenn wir uns mit dem Konzept einer Zeile einer Datei oder einer Datei als Textdatei befassen (dh, eine Textdatei ist eine Organisation von Null) oder mehr Zeilen, und eine Zeile, die wir kennen, muss mit einer <neuen Zeile>) enden.
Ein typisches Beispiel :
wc -l filename
.Aus dem
wc
Handbuch lesen wir:Was sind die Auswirkungen auf JavaScript, HTML und CSS - Dateien dann sein , dass sie Text - Dateien?
In Browsern, modernen IDEs und anderen Front-End-Anwendungen gibt es keine Probleme beim Überspringen von EOL bei EOF. Die Anwendungen analysieren die Dateien ordnungsgemäß. Da nicht alle Betriebssysteme dem POSIX-Standard entsprechen müssen, ist es für Nicht-Betriebssystem-Tools (z. B. Browser) unpraktisch, Dateien gemäß dem POSIX-Standard (oder einem beliebigen Standard auf Betriebssystemebene) zu verarbeiten.
Infolgedessen können wir relativ sicher sein, dass EOL bei EOF auf Anwendungsebene praktisch keine negativen Auswirkungen hat - unabhängig davon, ob es unter einem UNIX-Betriebssystem ausgeführt wird.
An dieser Stelle können wir mit Sicherheit sagen, dass das Überspringen von EOL bei EOF sicher ist, wenn auf der Clientseite mit JS, HTML, CSS gearbeitet wird. Tatsächlich können wir feststellen, dass das Minimieren einer dieser Dateien, die keine <newline> enthalten, sicher ist.
Wir können noch einen Schritt weiter gehen und sagen, dass NodeJS auch den POSIX-Standard nicht einhalten kann, da es in nicht POSIX-kompatiblen Umgebungen ausgeführt werden kann.
Was bleibt uns dann übrig? Werkzeuge auf Systemebene.
Dies bedeutet, dass nur Probleme mit Tools auftreten können, die sich bemühen, ihre Funktionalität an die Semantik von POSIX anzupassen (z. B. Definition einer Linie wie in gezeigt
wc
).Trotzdem haften nicht alle Shells automatisch an POSIX. Bash verwendet beispielsweise nicht standardmäßig das POSIX-Verhalten. Es gibt einen Schalter, um es zu aktivieren :
POSIXLY_CORRECT
.Denkanstöße zum Wert von EOL als <newline>: https://www.rfc-editor.org/old/EOLstory.txt
Lassen Sie uns Folgendes in Betracht ziehen, um auf der Werkzeugspur zu bleiben:
Lassen Sie uns mit einer Datei arbeiten, die keine EOL hat. Zum jetzigen Zeitpunkt ist die Datei in diesem Beispiel ein minimiertes JavaScript ohne EOL.
Beachten Sie, dass die
cat
Dateigröße genau die Summe der einzelnen Teile ist. Wenn die Verkettung von JavaScript-Dateien ein Problem für JS-Dateien darstellt, ist es besser, jede JavaScript-Datei mit einem Semikolon zu starten.Wie jemand anderes in diesem Thread erwähnt hat: Was ist, wenn Sie
cat
zwei Dateien möchten, deren Ausgabe nur eine Zeile statt zwei ist? Mit anderen Worten,cat
tut, was es tun soll.Das
man
voncat
erwähnt nur das Lesen von Eingaben bis zu EOF, nicht <newline>. Beachten Sie, dass beim-n
Umschalten voncat
auch eine nicht <newline> terminierte Zeile (oder unvollständige Zeile ) als Zeile ausgedruckt wird - dh , die Zählung beginnt bei 1 (gemäßman
.).Nachdem wir nun verstanden haben, wie POSIX eine Linie definiert , wird dieses Verhalten mehrdeutig oder nicht mehr konform.
Wenn Sie den Zweck und die Konformität eines bestimmten Tools verstehen, können Sie feststellen, wie wichtig es ist, Dateien mit einer EOL zu beenden. In C, C ++, Java (JARs) usw. schreiben einige Standards eine neue Zeile für die Gültigkeit vor - für JS, HTML, CSS gibt es keinen solchen Standard.
Anstatt beispielsweise
wc -l filename
eine zu verwendenawk '{x++}END{ print x}' filename
, können Sie sicher sein, dass der Erfolg der Aufgabe nicht durch eine Datei gefährdet wird, die wir möglicherweise verarbeiten möchten, die wir nicht geschrieben haben (z. B. eine Drittanbieter-Bibliothek wie die minimierte JS, die wir erstellt habencurl
) - es sei denn, unsere Die Absicht war wirklich, Zeilen im POSIX-konformen Sinne zu zählen.Fazit
Es wird nur sehr wenige reale Anwendungsfälle geben, in denen sich das Überspringen von EOL bei EOF für bestimmte Textdateien wie JS, HTML und CSS - wenn überhaupt - negativ auswirkt. Wenn wir uns darauf verlassen, dass <newline> vorhanden ist, beschränken wir die Zuverlässigkeit unserer Werkzeuge nur auf die Dateien, die wir erstellen, und öffnen uns potenziellen Fehlern, die durch Dateien von Drittanbietern verursacht werden.
Moral der Geschichte: Ingenieurwerkzeuge, die nicht die Schwäche haben, sich bei EOF auf EOL zu verlassen.
Sie können gerne Anwendungsfälle für JS, HTML und CSS veröffentlichen, in denen wir untersuchen können, wie sich das Überspringen von EOL nachteilig auswirkt.
quelle
Es kann mit dem Unterschied zusammenhängen zwischen :
Wenn jede Zeile mit einem Zeilenende endet, wird beispielsweise vermieden, dass durch die Verkettung von zwei Textdateien die letzte Zeile der ersten Zeile in die erste Zeile der zweiten Zeile übergeht.
Außerdem kann ein Editor beim Laden prüfen, ob die Datei am Zeilenende endet, sie in der lokalen Option 'eol' speichern und beim Schreiben der Datei verwenden.
Vor einigen Jahren (2005) haben viele Redakteure (ZDE, Eclipse, Scite, ...) diese endgültige EOL "vergessen", was nicht sehr geschätzt wurde .
Nicht nur das, sondern sie interpretierten diese endgültige EOL falsch als "Neue Zeile beginnen" und zeigen tatsächlich eine andere Zeile an, als ob sie bereits vorhanden wäre.
Dies war bei einer 'richtigen' Textdatei mit einem gut erzogenen Texteditor wie vim sehr gut sichtbar, verglichen mit dem Öffnen in einem der oben genannten Editoren. Es wurde eine zusätzliche Zeile unter der letzten Zeile der Datei angezeigt. Sie sehen so etwas:
quelle
Einige Tools erwarten dies. Erwartet zum Beispiel
wc
Folgendes:quelle
wc
dies nicht erwartet wird, da es einfach innerhalb der POSIX-Definition einer "Linie" funktioniert, im Gegensatz zum intuitiven Verständnis der meisten Leute von "Linie".wc -l
zu drucken1
, aber einige Leute könnten sagen, der zweite Fall sollte gedruckt werden2
.\n
als Zeilenabschluss und nicht als Zeilentrennzeichen vorstellen, wie es POSIX / UNIX tut, ist es absolut verrückt, zu erwarten, dass der zweite Fall 2 druckt.Grundsätzlich gibt es viele Programme, die Dateien nicht korrekt verarbeiten, wenn sie nicht die endgültige EOL EOF erhalten.
GCC warnt Sie davor, da dies als Teil des C-Standards erwartet wird. (Abschnitt 5.1.1.2 anscheinend)
Compiler-Warnung "Kein Zeilenumbruch am Dateiende"
quelle
Dies stammt aus den frühen Tagen, als einfache Terminals verwendet wurden. Das Zeilenumbruchzeichen wurde verwendet, um ein "Flush" der übertragenen Daten auszulösen.
Heute wird das Newline-Zeichen nicht mehr benötigt. Sicher, viele Apps haben immer noch Probleme, wenn der Zeilenumbruch nicht vorhanden ist, aber ich würde das als Fehler in diesen Apps betrachten.
Wenn Sie jedoch ein Textdateiformat haben, in dem Sie die neue Zeile benötigen , erhalten Sie eine einfache Datenüberprüfung sehr günstig: Wenn die Datei mit einer Zeile endet, die am Ende keine neue Zeile enthält, wissen Sie, dass die Datei fehlerhaft ist. Mit nur einem zusätzlichen Byte pro Zeile können Sie fehlerhafte Dateien mit hoher Genauigkeit und fast ohne CPU-Zeit erkennen.
quelle
Ein separater Anwendungsfall: Wenn Ihre Textdatei versioniert ist (in diesem Fall speziell unter Git, obwohl dies auch für andere gilt). Wenn am Ende der Datei Inhalt hinzugefügt wird, wurde die Zeile, die zuvor die letzte Zeile war, so bearbeitet, dass sie ein Zeilenumbruchzeichen enthält. Dies bedeutet, dass in
blame
der Datei, um herauszufinden, wann diese Zeile zuletzt bearbeitet wurde, der Textzusatz und nicht das Commit angezeigt wird, das Sie tatsächlich sehen wollten.quelle
\n
). Problem gelöst.Zusätzlich zu den oben genannten praktischen Gründen würde es mich nicht wundern, wenn die Urheber von Unix (Thompson, Ritchie et al.) Oder ihre Multics-Vorgänger erkennen würden, dass es einen theoretischen Grund gibt, Zeilenabschlusszeichen anstelle von Zeilenabscheidern zu verwenden: Mit Zeile Terminatoren können Sie alle möglichen Dateien von Zeilen codieren. Bei Zeilentrennzeichen gibt es keinen Unterschied zwischen einer Datei mit null Zeilen und einer Datei mit einer einzelnen leeren Zeile. Beide sind als Datei mit null Zeichen codiert.
Die Gründe sind also:
wc -l
Zählt beispielsweise keine letzte "Zeile", wenn sie nicht mit einer neuen Zeile endet.cat
funktioniert es einfach und es funktioniert ohne Komplikationen. Es werden nur die Bytes jeder Datei kopiert, ohne dass eine Interpretation erforderlich ist. Ich glaube nicht, dass es ein DOS-Äquivalent zu gibtcat
. Mitcopy a+b c
wird die letzte Dateizeilea
mit der ersten Dateizeile zusammengeführtb
.quelle
Ich habe mich das jahrelang selbst gefragt. Aber ich bin heute auf einen guten Grund gestoßen.
Stellen Sie sich eine Datei mit einem Datensatz in jeder Zeile vor (z. B. eine CSV-Datei). Und dass der Computer am Ende der Datei Aufzeichnungen schrieb. Aber es stürzte plötzlich ab. Gee war die letzte Zeile komplett? (keine schöne Situation)
Wenn wir jedoch immer die letzte Zeile beenden, wissen wir es (überprüfen Sie einfach, ob die letzte Zeile beendet ist). Andernfalls müssten wir wahrscheinlich jedes Mal die letzte Zeile verwerfen, nur um sicher zu gehen.
quelle
Vermutlich einfach, dass irgendein Parsing-Code damit gerechnet hat.
Ich bin mir nicht sicher, ob ich es als "Regel" betrachten würde, und es ist sicherlich nichts, woran ich mich religiös halte. Der sinnvollste Code kann Text (einschließlich Codierungen) zeilenweise (beliebige Zeilenenden) mit oder ohne Zeilenumbruch in der letzten Zeile analysieren.
In der Tat - wenn Sie mit einer neuen Zeile enden: Gibt es (theoretisch) eine leere letzte Zeile zwischen der EOL und der EOF? Einer zum Nachdenken ...
quelle
Es gibt auch ein praktisches Programmierproblem mit Dateien, denen am Ende Zeilenumbrüche fehlen: Der integrierte
read
Bash (ich weiß nichts über andereread
Implementierungen) funktioniert nicht wie erwartet:Dies druckt nur
foo
! Der Grund dafür ist, dass beimread
Aufrufen der letzten Zeile der Inhalt in den$line
Exit-Code 1 geschrieben wird, dieser jedoch zurückgegeben wird, da er EOF erreicht hat. Dies unterbricht diewhile
Schleife, sodass wir dasecho $line
Teil nie erreichen . Wenn Sie mit dieser Situation umgehen möchten, müssen Sie Folgendes tun:Führen Sie das aus,
echo
wenn diesread
aufgrund einer nicht leeren Zeile am Ende der Datei fehlgeschlagen ist. In diesem Fall gibt es natürlich eine zusätzliche neue Zeile in der Ausgabe, die nicht in der Eingabe enthalten war.quelle
Auch von vielen ausgedrückt, weil:
Viele Programme verhalten sich nicht gut oder schlagen ohne fehl.
Selbst Programme, die eine Datei gut verarbeiten, haben kein Ende
'\n'
. Die Funktionalität des Tools entspricht möglicherweise nicht den Erwartungen des Benutzers - was in diesem Eckfall unklar sein kann.Programme verbieten Final selten
'\n'
(ich kenne keine).Dies wirft jedoch die nächste Frage auf:
Am wichtigsten - Schreiben Sie keinen Code, der davon ausgeht, dass eine Textdatei mit einem Zeilenumbruch endet . Die Annahme, dass eine Datei einem Format entspricht, führt zu Datenbeschädigung, Hackerangriffen und Abstürzen. Beispiel:
Wenn die letzte Nachverfolgung
'\n'
erforderlich ist, machen Sie den Benutzer auf seine Abwesenheit und die ergriffenen Maßnahmen aufmerksam. IOWs, überprüfen Sie das Dateiformat. Hinweis: Dies kann eine Begrenzung der maximalen Zeilenlänge, Zeichencodierung usw. beinhalten.Definieren Sie klar und deutlich, wie der Code mit einem fehlenden Finale umgeht
'\n'
.Generieren Sie nach Möglichkeit keine Datei, der das Ende fehlt
'\n'
.quelle
Es ist sehr spät hier, aber ich hatte nur einen Fehler in der Dateiverarbeitung und der kam, weil die Dateien nicht mit einem leeren Zeilenumbruch endeten. Wir haben Textdateien mit verarbeitet
sed
undsed
die letzte Zeile in der Ausgabe weggelassen, was zu einer ungültigen JSON-Struktur führte und den Rest des Prozesses zum Fehlschlagen brachte.Alles was wir machten war:
Es gibt eine Beispieldatei, die sagt:
foo.txt
mit etwasjson
Inhalt darin.Die Datei wurde auf einem Witwencomputer erstellt, und Fensterskripte verarbeiteten diese Datei mit PowerShell-Befehlen. Alles gut.
Wenn wir dieselbe Datei mit dem
sed
Befehl verarbeitet habensed 's|value|newValue|g' foo.txt > foo.txt.tmp
Die neu generierte Datei war
und Boom, es schlug der Rest der Prozesse wegen des ungültigen JSON fehl.
Es ist daher immer eine gute Praxis, Ihre Datei mit einer leeren neuen Zeile zu beenden.
quelle
Ich hatte immer den Eindruck, dass die Regel aus den Tagen stammte, als es schwierig war, eine Datei ohne endenden Zeilenumbruch zu analysieren. Das heißt, Sie würden am Ende Code schreiben, bei dem ein Zeilenende durch das EOL-Zeichen oder EOF definiert wurde. Es war einfach einfacher anzunehmen, dass eine Zeile mit EOL endete.
Ich glaube jedoch, dass die Regel von C-Compilern abgeleitet ist, die die Newline benötigen. Und wie in der Compiler-Warnung "Keine neue Zeile am Ende der Datei" angegeben , fügt #include keine neue Zeile hinzu.
quelle
Stellen Sie sich vor, die Datei wird verarbeitet, während die Datei noch von einem anderen Prozess generiert wird.
Es könnte damit zu tun haben? Ein Flag, das angibt, dass die Datei zur Verarbeitung bereit ist.
quelle
Ich persönlich mag neue Zeilen am Ende von Quellcodedateien.
Es kann seinen Ursprung in Linux oder allen UNIX-Systemen haben. Ich erinnere mich an Kompilierungsfehler (gcc, wenn ich mich nicht irre), weil Quellcodedateien nicht mit einer leeren neuen Zeile endeten. Warum es so gemacht wurde, muss man sich fragen.
quelle
IMHO, es ist eine Frage des persönlichen Stils und der Meinung.
In alten Tagen habe ich diese Newline nicht gesetzt. Ein gespeicherter Charakter bedeutet mehr Geschwindigkeit durch dieses 14,4-KB-Modem.
Später habe ich diese neue Zeile eingefügt, damit es einfacher ist, die letzte Zeile mit Umschalt + Abwärtspfeil auszuwählen.
quelle