Warum sollten Textdateien mit einem Zeilenumbruch enden?


1468

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?


30
nur ein Trottel. Es ist keine "neue Zeile" am Ende der Datei. Es ist ein "Zeilenumbruch" am Ende der letzten Zeile. Siehe auch die beste Antwort auf eine verwandte Frage: stackoverflow.com/questions/16222530/…
gcb

346
Nur um noch mehr zu picken, schrieb er nicht wirklich "neue Zeile", er schrieb "neue Zeile", was richtig ist.
Sindrenm

5
Ich bin nicht vertraut, aber ich frage mich, ob die Anzahl der Fälle, in denen diese überflüssige Newline tatsächlich Dinge kaputt macht, für meinen Geschmack etwas zu hoch ist
Tobibeer

2
Ich verwende derzeit Node.js-Streams, um Klartextdaten zeilenweise zu analysieren, und das Fehlen eines Zeilenumbruchs am Terminal ist ärgerlich, da ich zusätzliche Logik hinzufügen muss, wenn die Eingabeseite des Streams fertig ist / geschlossen, um sicherzustellen, dass die letzte Zeile verarbeitet wird.
Mark K Cowan

23
Die Art und Weise Unix Hinblick auf ihr allgemeines Verhalten am Ende der Dateien ist wie folgt: \ n Zeichen Zeilen nicht starten; stattdessen beenden sie sie. \ N ist also ein Zeilenendezeichen, kein Zeilentrennzeichen. Die erste Zeile (wie alle Zeilen) benötigt kein \ n, um sie zu starten. Die letzte Zeile (wie alle Zeilen) benötigt ein \ n, um sie zu beenden. Ein \ n am Ende der Datei erstellt keine zusätzliche Zeile. Manchmal fügen Texteditoren dort jedoch eine sichtbare Leerzeile hinzu. Sogar Emacs tun dies optional .
MarkDBlackwell

Antworten:


1382

Denn so definiert der POSIX-Standard eine Linie :

3.206 Linie
Eine Folge von null oder mehr Nicht-<newline> -Zeichen plus einem abschließenden <newline> -Zeichen.

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:

$ more a.txt
foo
$ more b.txt
bar$ more c.txt
baz
$ cat {a,b,c}.txt
foo
barbaz

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 cates viel schwieriger , Befehle wie nützlich zu machen: Wie erstellen Sie einen Befehl, um Dateien so zu verketten, dass

  1. Der Start jeder Datei wird in eine neue Zeile gesetzt, was in 95% der Fälle gewünscht wird. aber
  2. Es ermöglicht das Zusammenführen der letzten und ersten Zeile von zwei Dateien, wie im obigen Beispiel zwischen b.txtund c.txt?

Natürlich ist dies lösbar, aber Sie müssen die Verwendung catkomplexer gestalten (z. B. durch Hinzufügen von Positionsbefehlszeilenargumenten cat 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.


9
Obwohl die Korrektur jetzt ziemlich unpraktisch ist, hat POSIX bei der Definition der Linie eindeutig einen Fehler gemacht - als Beweis für die Anzahl der Fragen zu diesem Problem. Eine Zeile sollte als null oder mehr Zeichen definiert sein, die mit <eol>, <eof> oder <eol> <eof> abgeschlossen sind. Die Komplexität des Parsers ist kein berechtigtes Anliegen. Komplexität sollte, wo immer möglich, vom Kopf des Programmierers in die Bibliothek verlagert werden.
Doug Coburn

23
@DougCoburn Diese Antwort hatte früher eine ausführliche technische Diskussion, in der erklärt wurde, warum dies falsch ist und warum POSIX das Richtige getan hat. Leider wurden diese Kommentare offenbar kürzlich von einem übereifrigen Moderator gelöscht. Kurz gesagt, es geht nicht darum, Komplexität zu analysieren. Vielmehr macht es Ihre Definition viel schwieriger, Tools zu erstellen, beispielsweise catauf nützliche und konsistente Weise.
Konrad Rudolph

8
@Leon Bei der POSIX-Regel geht es darum, Kantenfälle zu reduzieren. Und das macht es so schön. Ich bin eigentlich etwas ratlos, wie die Leute das nicht verstehen: Es ist die einfachste, selbstkonsistente Definition einer Linie.
Konrad Rudolph

6
@BT Ich denke, Sie gehen davon aus, dass mein Beispiel für einen bequemeren Workflow der Grund für die Entscheidung ist. Es ist nicht, es ist nur eine Konsequenz. Der Grund dafür ist, dass die POSIX-Regel die einfachste Regel ist und die Behandlung von Zeilen in einem Parser am einfachsten macht. Der einzige Grund, warum wir überhaupt darüber diskutieren, ist, dass Windows es anders macht und dass es infolgedessen zahlreiche Tools gibt, die bei POSIX-Dateien fehlschlagen. Wenn alle POSIX machen würden, gäbe es kein Problem. Dennoch beschweren sich die Leute über POSIX, nicht über Windows.
Konrad Rudolph

7
@BT Ich beziehe mich nur auf Windows, um auf die Fälle hinzuweisen, in denen POSIX-Regeln keinen Sinn ergeben (mit anderen Worten, ich habe Ihnen einen Knochen geworfen). Ich bin mehr als glücklich, es in dieser Diskussion nie wieder zu erwähnen. Aber dann macht Ihre Behauptung noch weniger Sinn: Auf POSIX-Plattformen macht es einfach keinen Sinn, Textdateien mit unterschiedlichen Konventionen für Zeilenenden zu diskutieren, da es keinen Grund gibt, sie zu erstellen. Was ist der Vorteil? Es gibt buchstäblich keine. - Zusammenfassend verstehe ich den Hass, den diese Antwort (oder die POSIX-Regel) hervorruft , wirklich nicht. Um ehrlich zu sein, ist es völlig irrational.
Konrad Rudolph

282

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.

Der C-Sprachstandard besagt, dass eine Quelldatei, die nicht leer ist, mit einem Zeilenumbruchzeichen enden darf, dem nicht unmittelbar ein Backslash-Zeichen vorangestellt werden darf.

Da dies eine "soll" -Klausel ist, müssen wir eine Diagnosemeldung für einen Verstoß gegen diese Regel ausgeben.

Dies ist in Abschnitt 2.1.1.2 des ANSI C 1989-Standards enthalten. Abschnitt 5.1.1.2 der Norm ISO C 1999 (und wahrscheinlich auch der Norm ISO C 1990).

Referenz: Das GCC / GNU-Mail-Archiv .


17
Bitte schreiben Sie dann gute Programme, die entweder das Einfügen dieser neuen Zeile bei Bedarf während der Verarbeitung ermöglichen oder in der Lage sind, "fehlende" ordnungsgemäß zu behandeln ... die tatsächlich nicht fehlen
tobibeer

4
@BilltheLizard, Was sind einige Beispiele für "Einige Programme haben Probleme beim Verarbeiten der letzten Zeile einer Datei, wenn sie nicht beendet ist" ?
Pacerier

4
@Pacerier wc -lzählt die letzte Zeile einer Datei nicht, wenn sie nicht beendet ist. Auch catbeitreten 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.
Bill the Lizard

2
@ BilltheLizard, ich meine, wcwurde bereits erwähnt ....
Pacerier

2
@ BilltheLizard, meine schlechte, um zu verdeutlichen: Was sind einige Beispiele für Programme, die Probleme haben, die letzte Zeile einer Datei zu verarbeiten, wenn sie nicht mit einer neuen Zeile beendet ist (außer denen, die bereits im Thread wie catund massenweise erwähnt wurden wc)?
Pacerier

116

Diese Antwort ist eher ein Versuch einer technischen Antwort als eine Meinung.

Wenn wir POSIX-Puristen sein wollen, definieren wir eine Linie als:

Eine Folge von null oder mehr Nicht-<newline> -Zeichen plus einem abschließenden <newline> -Zeichen.

Quelle: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206

Eine unvollständige Zeile als:

Eine Folge von einem oder mehreren Nicht-<newline> -Zeichen am Ende der Datei.

Quelle: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195

Eine Textdatei als:

Eine Datei, die Zeichen enthält, die in null oder mehr Zeilen organisiert sind. Die Zeilen enthalten keine NUL-Zeichen und keines darf die Länge von {LINE_MAX} Bytes überschreiten, einschließlich des Zeichens <newline>. Obwohl POSIX.1-2008 nicht zwischen Textdateien und Binärdateien unterscheidet (siehe ISO C-Standard), erzeugen viele Dienstprogramme nur vorhersehbare oder aussagekräftige Ausgaben, wenn sie mit Textdateien arbeiten. Die Standarddienstprogramme mit solchen Einschränkungen geben in ihren Abschnitten STDIN oder INPUT FILES immer "Textdateien" an.

Quelle: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397

Eine Zeichenfolge als:

Eine zusammenhängende Folge von Bytes, die mit dem ersten Nullbyte abgeschlossen sind und dieses enthalten.

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 wcHandbuch lesen wir:

Eine Zeile ist definiert als eine Zeichenfolge, die durch ein <neues> Zeichen begrenzt wird.

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.

curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o x.js
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o y.js

$ cat x.js y.js > z.js

-rw-r--r--  1 milanadamovsky   7905 Aug 14 23:17 x.js
-rw-r--r--  1 milanadamovsky   7905 Aug 14 23:17 y.js
-rw-r--r--  1 milanadamovsky  15810 Aug 14 23:18 z.js

Beachten Sie, dass die catDateigröß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 catzwei Dateien möchten, deren Ausgabe nur eine Zeile statt zwei ist? Mit anderen Worten, cattut, was es tun soll.

Das manvon caterwähnt nur das Lesen von Eingaben bis zu EOF, nicht <newline>. Beachten Sie, dass beim -nUmschalten von catauch eine nicht <newline> terminierte Zeile (oder unvollständige Zeile ) als Zeile ausgedruckt wird - dh , die Zählung beginnt bei 1 (gemäß man.).

-n Nummerieren Sie die Ausgangsleitungen beginnend mit 1.

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 filenameeine zu verwenden awk '{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 haben curl) - 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.


2
POSIX ist in der Frage nicht markiert ... was ist mit MVS / OS-Zeilenenden? oder MS-DOS-Leitungsenden? Übrigens erlauben alle bekannten Posix-Systeme Textdateien ohne endgültiges Zeilenende (kein Fall eines posix-konformen Anspruchssystems gefunden, bei dem "Textdatei" im Kernel eine Sonderbehandlung hat, um eine richtige neue Zeile einzufügen, falls dies nicht der Fall ist it)
Luis Colorado

62

Es kann mit dem Unterschied zusammenhängen zwischen :

  • Textdatei (jede Zeile soll mit einem Zeilenende enden)
  • Binärdatei (es gibt keine echten "Zeilen", von denen zu sprechen ist, und die Länge der Datei muss beibehalten werden)

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:

1 first line
2 middle line
3 last line
4

11
+1. Ich habe diese SO-Frage gefunden, als ich genau dieses Problem hatte. Es ist sehr ärgerlich von Eclipse, diese "falsche" letzte Zeile anzuzeigen, und wenn ich sie entferne, beschwert sich git (und alle anderen Unix-Tools, die EOL erwarten). Beachten Sie auch, dass dies nicht nur im Jahr 2005 der Fall ist: Eclipse 4.2 Juno hat dieses Problem immer noch.
MestreLion

@MestreLion, Fortsetzung bei stackoverflow.com/questions/729692/…
Pacerier

46

Einige Tools erwarten dies. Erwartet zum Beispiel wcFolgendes:

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1

22
Ich würde nicht "einige" sagen, ich sage, die meisten Tools erwarten das für Textdateien, wenn nicht alle. Katze, Git, Diff, WC, Grep, Sed ... die Liste ist riesig
MestreLion

Vielleicht könnte man sagen, dass wcdies nicht erwartet wird, da es einfach innerhalb der POSIX-Definition einer "Linie" funktioniert, im Gegensatz zum intuitiven Verständnis der meisten Leute von "Linie".
Guildenstern

@Guildenstern Die intuitive Definition wäre, in beiden Fällen wc -lzu drucken 1, aber einige Leute könnten sagen, der zweite Fall sollte gedruckt werden 2.
Flimm

@Flimm Wenn Sie sich \nals Zeilenabschluss und nicht als Zeilentrennzeichen vorstellen, wie es POSIX / UNIX tut, ist es absolut verrückt, zu erwarten, dass der zweite Fall 2 druckt.
Semikolon

21

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"


5
GCC ist nicht in der Lage, die Datei zu verarbeiten, sondern muss die Warnung als Teil des C-Standards ausgeben.
Bill the Lizard

IIRC, MSVC 2005 beschwerte sich über C-Dateien, die mit unvollständigen Zeilen endeten und sich möglicherweise weigerten, diese zu kompilieren.
Mark K Cowan

16

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.


15
heute das Newline bei EOF für Text - Dateien kann keine Voraussetzung, aber es ist eine nützliche Konvention , dass die meisten Unix - Tools arbeiten zusammen mit konsistenten Ergebnissen macht. Es ist überhaupt kein Fehler.
MestreLion

14
Viele von uns verwenden überhaupt keine Unix-Tools und es ist uns egal.
DaveWalley

12
Es sind nicht nur Unix-Tools, jedes Tool funktioniert besser und / oder wird einfacher codiert, wenn es sinnvolle Dateiformate annehmen kann.
Sam Watkins

2
@ Sam Watkins Ich bin damit einverstanden, dass einfache, gut definierte Formate gut sind. Der Code muss jedoch noch überprüft werden und darf nicht davon ausgehen, dass die Daten formatkonform sind.
chux

8
@MestreLion Dies ist ein nutzloses Erbe aus einer Reihe von schlechten Tools, die dummen Standards entsprechen. Diese Artefakte extremistischer Programmierung (dh alles Datei! Alles sollte Klartext sprechen!) Starb nicht bald nach ihrer Erfindung, da sie zu einem bestimmten Zeitpunkt der Geschichte die einzigen verfügbaren Werkzeuge dieser Art waren. C wurde von C ++ abgelöst, es ist kein Teil von POSIX, es erfordert keine EOL bei EOF und seine Verwendung wird (offensichtlich) von * nix-Luddisten abgeraten.
polkovnikov.ph

14

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 blameder Datei, um herauszufinden, wann diese Zeile zuletzt bearbeitet wurde, der Textzusatz und nicht das Commit angezeigt wird, das Sie tatsächlich sehen wollten.


1
Diff und Blame sollten nur aktualisiert werden, um "neue Zeilen" und nicht "neue Zeilen" zu erkennen ( \n). Problem gelöst.
Andrew

1
Sie können das Tag -w verwenden, um Leerzeichenänderungen zu ignorieren, diese sind jedoch nicht die Standardeinstellungen.
Robin Whittleton

11

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:

  1. Denn so definiert es POSIX.
  2. Weil einige Tools es erwarten oder sich ohne es "schlecht benehmen". wc -lZählt beispielsweise keine letzte "Zeile", wenn sie nicht mit einer neuen Zeile endet.
  3. Weil es einfach und bequem ist. Unter Unix catfunktioniert 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 gibt cat. Mit copy a+b cwird die letzte Dateizeile amit der ersten Dateizeile zusammengeführt b.
  4. Weil eine Datei (oder ein Stream) mit null Zeilen von einer Datei mit einer leeren Zeile unterschieden werden kann.

11

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.


10

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 ...


12
Es ist keine Regel, es ist eine Konvention: Eine Zeile endet mit einem Zeilenende . Also nein, es gibt keine "leere letzte Zeile" zwischen EOL und EOF.
MestreLion

4
@MestreLion: Das betreffende Zeichen heißt jedoch nicht "Zeilenende", sondern "Zeilenumbruch" und / oder "Zeilenvorschub". Ein Zeilentrennzeichen, kein Zeilenendezeichen. Und das Ergebnis ist eine letzte leere Zeile.
Ben Voigt

2
Kein (vernünftiges) Werkzeug würde die letzte EOL (CR, LF usw.) einer Datei als zusätzliche leere Zeile zählen. Und alle POSIX-Tools zählen die letzten Zeichen einer Datei nicht als Zeile, wenn keine EOL-Endung vorhanden ist. Unabhängig von der EOL - Zeichen Namen „Zeilenvorschub“ oder „Carriage Return“ zu sein (es gibt keinen Charakter namens „Newline“) für alle praktischen puposes sinnvolle Werkzeuge , um es als eine Linie behandeln Terminator , nicht als Zeilentrennzeichen .
MestreLion

2
@MestreLion, Sind Sie sicher, dass "Line Terminator" vernünftig ist? Besorgen Sie sich ein paar Nicht-Programmierer und machen Sie eine kurze Umfrage. Sie werden schnell feststellen, dass das Konzept der Linien dem Konzept der "Linientrennzeichen" näher kommt. Das Konzept des "Line Terminator" ist einfach komisch .
Pacerier

4
@Sahuagin: Dies ist nicht meine Ansicht, so definiert der POSIX-Standard eine Linie. Eine leere Datei mit 0 Bytes hat 0 Zeilen, daher keine EOL, und für eine Datei, die nur eine einzige leere Zeile enthält , ist eine EOL erforderlich. Beachten Sie auch, dass dies nur relevant ist, wenn Sie die Zeilen in einer Datei zählen möchten , da Sie mit jedem Editor offensichtlich zur nächsten (oder ersten) Zeile "gelangen" können, unabhängig davon, ob dort bereits eine EOL vorhanden ist.
MestreLion

10

Es gibt auch ein praktisches Programmierproblem mit Dateien, denen am Ende Zeilenumbrüche fehlen: Der integrierte readBash (ich weiß nichts über andere readImplementierungen) funktioniert nicht wie erwartet:

printf $'foo\nbar' | while read line
do
    echo $line
done

Dies druckt nurfoo ! Der Grund dafür ist, dass beim readAufrufen der letzten Zeile der Inhalt in den $lineExit-Code 1 geschrieben wird, dieser jedoch zurückgegeben wird, da er EOF erreicht hat. Dies unterbricht die whileSchleife, sodass wir das echo $lineTeil nie erreichen . Wenn Sie mit dieser Situation umgehen möchten, müssen Sie Folgendes tun:

while read line || [ -n "${line-}" ]
do
    echo $line
done < <(printf $'foo\nbar')

Führen Sie das aus, echowenn dies readaufgrund 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.


9

Warum sollten (Text-) Dateien mit einem Zeilenumbruch enden?

Auch von vielen ausgedrückt, weil:

  1. Viele Programme verhalten sich nicht gut oder schlagen ohne fehl.

  2. 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.

  3. Programme verbieten Final selten '\n'(ich kenne keine).


Dies wirft jedoch die nächste Frage auf:

Was sollte Code mit Textdateien ohne Zeilenumbruch tun?

  1. 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:

    // 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
      ...
    }
    
  2. 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.

  3. Definieren Sie klar und deutlich, wie der Code mit einem fehlenden Finale umgeht '\n'.

  4. Generieren Sie nach Möglichkeit keine Datei, der das Ende fehlt '\n'.


4

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 sedund seddie 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.txtmit etwas jsonInhalt darin.

[{
    someProp: value
},
{
    someProp: value
}] <-- No newline here

Die Datei wurde auf einem Witwencomputer erstellt, und Fensterskripte verarbeiteten diese Datei mit PowerShell-Befehlen. Alles gut.

Wenn wir dieselbe Datei mit dem sedBefehl verarbeitet habensed 's|value|newValue|g' foo.txt > foo.txt.tmp

Die neu generierte Datei war

[{
    someProp: value
},
{
    someProp: value

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.


3

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.


0

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.


-4

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.


-6

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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.