Ich nehme an, dass jeder hier mit dem Sprichwort vertraut ist, dass alle Textdateien mit einem Zeilenumbruch enden sollten. Ich kenne diese "Regel" schon seit Jahren, aber ich habe mich immer gefragt, warum?
Antworten
Zu viele Anzeigen?Zusätzlich zu den oben genannten praktischen Gründen würde es mich nicht überraschen, wenn die Erfinder von Unix (Thompson, Ritchie, et al.) oder ihre Multics-Vorgänger erkannt hätten, dass es einen theoretischen Grund gibt, Zeilenterminatoren anstelle von Zeilentrennern zu verwenden: Mit Zeilenterminatoren kann man alle möglichen Zeilendateien kodieren. Mit Zeilentrennern gibt es keinen Unterschied zwischen einer Datei mit null Zeilen und einer Datei mit einer einzigen leeren Zeile; beide werden als eine Datei mit null Zeichen kodiert.
Das sind also die Gründe:
- Denn so ist es in POSIX definiert.
- Denn einige Werkzeuge erwarten sie oder verhalten sich ohne sie "falsch". Zum Beispiel,
wc -l
zählt eine letzte "Zeile" nicht, wenn sie nicht mit einem Zeilenumbruch endet. - Weil es einfach und bequem ist. Unter Unix,
cat
funktioniert einfach, und zwar ohne Komplikationen. Es werden einfach die Bytes jeder Datei kopiert, ohne dass eine Interpretation erforderlich ist. Ich glaube nicht, daß es ein DOS-Äquivalent gibt zucat
. Verwendung voncopy a+b c
wird am Ende die letzte Zeile der Dateia
mit der ersten Zeile der Dateib
. - Denn eine Datei (oder ein Stream) mit null Zeilen kann von einer Datei mit einer leeren Zeile unterschieden werden.
Vermutlich hat ein Parsing-Code einfach erwartet, dass er dort vorhanden ist.
Ich bin mir nicht sicher, ob ich das als "Regel" bezeichnen würde, und es ist sicherlich nicht etwas, an das ich mich religiös halte. Der meiste vernünftige Code weiß, wie man Text (einschließlich Kodierungen) zeilenweise analysiert (mit oder ohne Zeilenende), mit oder ohne Zeilenumbruch in der letzten Zeile.
In der Tat - wenn Sie mit einer neuen Zeile enden: Gibt es (theoretisch) eine leere letzte Zeile zwischen EOL und EOF? Eine Überlegung wert...
Es gibt auch ein praktisches Programmierproblem mit Dateien ohne Zeilenumbrüche am Ende: Die read
Bash eingebaut (ich weiß nicht, ob andere read
Implementierungen) funktioniert nicht wie erwartet:
printf $'foo\nbar' | while read line
do
echo $line
done
Dies druckt seulement foo
! Der Grund dafür ist, dass, wenn read
auf die letzte Zeile stößt, schreibt es den Inhalt in $line
gibt aber den Exit-Code 1 zurück, weil er EOF erreicht hat. Dies bricht die while
Schleife, so dass wir nie die echo $line
Teil. Wenn Sie diese Situation bewältigen wollen, müssen Sie Folgendes tun:
while read line || [ -n "${line-}" ]
do
echo $line
done < <(printf $'foo\nbar')
Das heißt, die echo
si le read
ist wegen einer nicht leeren Zeile am Ende der Datei fehlgeschlagen. Natürlich wird in diesem Fall ein zusätzlicher Zeilenumbruch in der Ausgabe erscheinen, der in der Eingabe nicht enthalten war.
Warum sollten (Text-)Dateien mit einem Zeilenumbruch enden?
Wie von vielen gut ausgedrückt, denn:
-
Viele Programme verhalten sich nicht gut oder scheitern ohne sie.
-
Selbst Programmen, die eine Datei gut verarbeiten können, fehlt ein Ende
'\n'
Die Funktionalität des Tools entspricht möglicherweise nicht den Erwartungen des Benutzers, die in diesem Fall unklar sein können. -
Programme selten nicht zulassen endgültig
'\n'
(Mir sind keine bekannt).
Dies wirft jedoch die nächste Frage auf:
Was soll der Code bei Textdateien ohne Zeilenumbruch tun?
-
Das Wichtigste - Schreiben Sie keinen Code, der davon ausgeht, dass eine Textdatei mit einem Zeilenumbruch endet. . Angenommen, eine Datei einem Format entspricht, führt zu Datenbeschädigung, Hackerangriffen und Abstürzen. Beispiel:
// Bad code while (fgets(buf, sizeof buf, instream)) { // What happens if there is no \n, buf[] is truncated leading to who knows what buf[strlen(buf) - 1] = '\0'; // attempt to rid trailing \n ... }
-
Wenn das letzte Wort am Ende
'\n'
benötigt wird, weisen Sie den Benutzer auf sein Fehlen und die ergriffene Maßnahme hin. D.h., überprüfen Sie das Format der Datei. Hinweis: Dies kann eine Begrenzung der maximalen Zeilenlänge, der Zeichenkodierung usw. beinhalten. -
Definieren Sie klar und dokumentieren Sie, wie der Code mit einer fehlenden Endung umgeht.
'\n'
. -
Möglichst nicht, erzeugen eine Datei, bei der die Endung fehlt
'\n'
.
Es ist schon sehr spät, aber ich hatte gerade einen Fehler bei der Dateiverarbeitung, und der kam daher, dass die Dateien nicht mit einem leeren Zeilenumbruch beendet wurden. Wir verarbeiteten Textdateien mit sed
y sed
ließ die letzte Zeile in der Ausgabe aus, was zu einer ungültigen json-Struktur führte und den Rest des Prozesses in einen Fehlerzustand versetzte.
Alles, was wir taten, war:
Es gibt eine Beispieldatei: foo.txt
mit einigen json
Inhalt darin.
[{
someProp: value
},
{
someProp: value
}] <-- No newline here
Die Datei wurde auf einem Windows-Computer erstellt, und Fensterskripte verarbeiteten diese Datei mit PowerShell-Befehlen. Alles gut.
Wenn wir dieselbe Datei mit sed
Befehl sed 's|value|newValue|g' foo.txt > foo.txt.tmp
Die neu erstellte Datei wurde
[{
someProp: value
},
{
someProp: value
und schon schlug der Rest der Prozesse wegen des ungültigen JSON fehl.
Es ist also immer eine gute Praxis, die Datei mit einer neuen Leerzeile zu beenden.