Pourquoi les fichiers texte devraient-ils se terminer par une nouvelle ligne?

1470

Je suppose que tout le monde ici connaît l'adage selon lequel tous les fichiers texte doivent se terminer par une nouvelle ligne. Je connais cette "règle" depuis des années mais je me suis toujours demandé - pourquoi?

Will Robertson
la source
30
juste une piqûre. ce n'est pas une "nouvelle ligne" à la fin du fichier. C'est un "saut de ligne" à la fin de la dernière ligne. Voir également la meilleure réponse à une question connexe: stackoverflow.com/questions/16222530/…
gcb
346
Juste pour pinailler un peu plus, il n'a pas vraiment écrit "nouvelle ligne", il a écrit "nouvelle ligne", ce qui est correct.
sindrenm
5
pas familier, mais je me demande en effet parce que le nombre de cas où cette nouvelle ligne superflue casse réellement les choses est un peu trop élevé à mes goûts
tobibeer
2
J'utilise actuellement des flux Node.js pour analyser les données en texte brut ligne par ligne, et l'absence de saut de ligne terminal est ennuyeux, car je dois ajouter une logique supplémentaire lorsque le côté entrée du flux est terminé / fermé afin de garantir le traitement de la dernière ligne.
Mark K Cowan
23
La façon dont Unix considère son comportement général à la fin des fichiers est la suivante: \ n les caractères ne commencent pas les lignes; au lieu de cela, ils y mettent fin. Donc, \ n est un terminateur de ligne, pas un séparateur de ligne. La première ligne (comme toutes les lignes) n'a pas besoin de \ n pour la démarrer. La dernière ligne (comme toutes les lignes) a besoin d'un \ n pour la terminer. Un \ n à la fin du fichier ne crée pas de ligne supplémentaire. Parfois, cependant, les éditeurs de texte y ajoutent une ligne vierge visible. Même emacs le fait, éventuellement .
MarkDBlackwell

Réponses:

1383

Parce que c'est ainsi que la norme POSIX définit une ligne :

3.206 Ligne
Une séquence de zéro ou plusieurs caractères non <nouvelle> plus un caractère <nouvelle> de fin.

Par conséquent, les lignes ne se terminant pas par un caractère de nouvelle ligne ne sont pas considérées comme des lignes réelles. C'est pourquoi certains programmes ont des problèmes pour traiter la dernière ligne d'un fichier s'il n'est pas terminé.

Il y a au moins un avantage important à cette directive lorsque vous travaillez sur un émulateur de terminal: tous les outils Unix attendent cette convention et fonctionnent avec elle. Par exemple, lors de la concaténation de fichiers avec cat, un fichier terminé par une nouvelle ligne aura un effet différent de celui sans:

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

Et, comme l'exemple précédent le montre également, lors de l'affichage du fichier sur la ligne de commande (par exemple via more), un fichier terminé par une nouvelle ligne se traduit par un affichage correct. Un fichier incorrectement terminé peut être tronqué (deuxième ligne).

Pour des raisons de cohérence, il est très utile de suivre cette règle - sinon, cela entraînera un travail supplémentaire lors de l'utilisation des outils Unix par défaut.


Pensez-y différemment: si les lignes ne sont pas terminées par un saut de ligne, rendre les commandes aussi catutiles est beaucoup plus difficile: comment créer une commande pour concaténer des fichiers de telle sorte que

  1. il place le début de chaque fichier sur une nouvelle ligne, ce que vous voulez 95% du temps; mais
  2. il permet de fusionner la dernière et la première ligne de deux fichiers, comme dans l'exemple ci-dessus entre b.txtet c.txt?

Bien sûr, cela peut être résolu, mais vous devez rendre l'utilisation de catplus complexe (en ajoutant des arguments de ligne de commande positionnels, par exemple cat a.txt --no-newline b.txt c.txt), et maintenant la commande plutôt que chaque fichier individuel contrôle la façon dont il est collé avec d'autres fichiers. Ce n'est certainement pas pratique.

… Ou vous devez introduire un caractère sentinelle spécial pour marquer une ligne qui est censée être poursuivie plutôt que terminée. Eh bien, maintenant vous êtes coincé avec la même situation que sur POSIX, sauf inversé (continuation de ligne plutôt que caractère de fin de ligne).


Maintenant, sur les systèmes non conformes à POSIX (de nos jours, c'est principalement Windows), le point est théorique: les fichiers ne se terminent généralement pas par une nouvelle ligne, et la définition (informelle) d'une ligne peut par exemple être «du texte séparé par des nouvelles lignes» (notez l'emphase). C'est tout à fait valable. Cependant, pour les données structurées (par exemple, le code de programmation), cela rend l'analyse plus compliquée: cela signifie généralement que les analyseurs doivent être réécrits. Si un analyseur a été écrit à l'origine avec la définition POSIX à l'esprit, il pourrait être plus facile de modifier le flux de jetons plutôt que l'analyseur - en d'autres termes, ajoutez un jeton de "nouvelle ligne artificielle" à la fin de l'entrée.

Konrad Rudolph
la source
9
Bien qu'il soit maintenant assez difficile de rectifier, POSIX a clairement fait une erreur lors de la définition de la ligne - comme preuve par le nombre de questions concernant cette question. Une ligne doit avoir été définie comme zéro ou plusieurs caractères terminés par <eol>, <eof> ou <eol> <eof>. La complexité de l'analyseur n'est pas une préoccupation valable. Dans la mesure du possible, la complexité doit être déplacée de la tête du programmeur vers la bibliothèque.
Doug Coburn
23
@DougCoburn Cette réponse avait l'habitude d'avoir une discussion technique exhaustive expliquant pourquoi c'est mal, et pourquoi POSIX a fait la bonne chose. Malheureusement, ces commentaires ont apparemment été récemment supprimés par un modérateur trop zélé. En bref, il ne s'agit pas d'analyser la complexité; votre définition rend plutôt beaucoup plus difficile la création d'outils, par exemple catd'une manière à la fois utile et cohérente.
Konrad Rudolph
8
@Leon La règle POSIX consiste à réduire les cas marginaux. Et il le fait magnifiquement. En fait, je ne comprends pas du tout comment les gens ne comprennent pas cela: c'est la définition la plus simple et cohérente d'une ligne.
Konrad Rudolph
6
@BT Je pense que vous supposez que mon exemple d'un flux de travail plus pratique est la raison de la décision. Ce n'est pas, c'est juste une conséquence. La raison en est que la règle POSIX est la règle la plus simple et qui rend la gestion des lignes dans un analyseur la plus simple. La seule raison pour laquelle nous avons même le débat est que Windows le fait différemment, et qu'en conséquence, il existe de nombreux outils qui échouent sur les fichiers POSIX. Si tout le monde faisait POSIX, il n'y aurait aucun problème. Pourtant, les gens se plaignent de POSIX, pas de Windows.
Konrad Rudolph
7
@BT Je ne fais référence qu'à Windows pour signaler les cas où les règles POSIX n'ont pas de sens (en d'autres termes, je vous jetais un os). Je suis plus qu'heureux de ne plus jamais le mentionner dans cette discussion. Mais votre affirmation est encore moins logique: sur les plates-formes POSIX, cela n'a tout simplement aucun sens de discuter de fichiers texte avec différentes conventions de fin de ligne, car il n'y a aucune raison de les produire. Quel est l'avantage? Il n'y en a littéralement pas. - En résumé, je ne comprends vraiment pas la haine que cette réponse (ou la règle POSIX) engendre. Pour être franc, c'est complètement irrationnel.
Konrad Rudolph
282

Chaque ligne doit se terminer par un caractère de nouvelle ligne, y compris la dernière. Certains programmes ont des problèmes de traitement de la dernière ligne d'un fichier s'il n'est pas terminé.

GCC l'avertit non pas parce qu'il ne peut pas traiter le fichier, mais parce qu'il doit le faire dans le cadre de la norme.

La norme du langage C indique qu'un fichier source qui n'est pas vide doit se terminer par un caractère de nouvelle ligne, qui ne doit pas être immédiatement précédé d'une barre oblique inverse.

Puisqu'il s'agit d'une clause "doit", nous devons émettre un message de diagnostic pour une violation de cette règle.

C'est dans la section 2.1.1.2 de la norme ANSI C 1989. Section 5.1.1.2 de la norme ISO C 1999 (et probablement aussi la norme ISO C 1990).

Référence: Les archives de messagerie GCC / GNU .

Bill le lézard
la source
17
veuillez alors écrire de bons programmes qui permettent soit d'insérer cette nouvelle ligne là où cela est nécessaire pendant le traitement, soit qui sont capables de gérer correctement ceux "manquants" ... qui ne sont en fait pas manquants
tobibeer
4
@BilltheLizard, Quels sont quelques exemples de "Certains programmes ont des problèmes de traitement de la dernière ligne d'un fichier s'il n'est pas terminé avec la nouvelle ligne" ?
Pacerier
4
@Pacerier wc -lne comptera pas la dernière ligne d'un fichier s'il n'est pas terminé. En outre, catjoignera la dernière ligne d'un fichier avec la première ligne du fichier suivant en une seule si la dernière ligne du premier fichier n'est pas terminée. À peu près n'importe quel programme qui recherche des nouvelles lignes comme délimiteur a le potentiel de gâcher cela.
Bill the Lizard
2
@BilltheLizard, je veux dire wca déjà été mentionné ....
Pacerier
2
@BilltheLizard, Mon mauvais, pour clarifier: quels sont quelques exemples de programmes qui ont des problèmes de traitement de la dernière ligne d'un fichier s'il n'est pas terminé par une nouvelle ligne (en plus de ceux qui ont déjà été mentionnés en masse sur le fil comme catet wc)?
Pacerier
116

Cette réponse est une tentative de réponse technique plutôt que d'opinion.

Si nous voulons être des puristes POSIX, nous définissons une ligne comme:

Une séquence de zéro ou plusieurs caractères non <nouvelle> plus un caractère <nouvelle> de fin.

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

Une ligne incomplète comme:

Une séquence d'un ou plusieurs caractères non <nouvelle> à la fin du fichier.

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

Un fichier texte comme:

Un fichier qui contient des caractères organisés en zéro ou plusieurs lignes. Les lignes ne contiennent pas de caractères NUL et aucune ne peut dépasser {LINE_MAX} octets de longueur, y compris le caractère <newline>. Bien que POSIX.1-2008 ne fasse pas de distinction entre les fichiers texte et les fichiers binaires (voir la norme ISO C), de nombreux utilitaires ne produisent une sortie prévisible ou significative que lorsqu'ils fonctionnent sur des fichiers texte. Les utilitaires standard qui ont de telles restrictions spécifient toujours des "fichiers texte" dans leurs sections STDIN ou INPUT FILES.

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

Une chaîne comme:

Une séquence contiguë d'octets terminée par et incluant le premier octet nul.

Source: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396

De cela, nous pouvons déduire que la seule fois où nous pourrons potentiellement rencontrer un type de problème, c'est si nous traitons le concept d'une ligne de fichier ou d'un fichier comme un fichier texte (étant donné qu'un fichier texte est une organisation de zéro ou plusieurs lignes, et une ligne que nous connaissons doit se terminer par un <newline>).

Exemple: wc -l filename.

Dans le wcmanuel, nous lisons:

Une ligne est définie comme une chaîne de caractères délimitée par un caractère <newline>.

Quelles sont les implications pour les fichiers JavaScript, HTML et CSS étant alors que ce sont des fichiers texte ?

Dans les navigateurs, les IDE modernes et les autres applications frontales, il n'y a aucun problème à ignorer EOL à EOF. Les applications analysent correctement les fichiers. Il doit, puisque tous les systèmes d'exploitation ne sont pas conformes à la norme POSIX, il serait donc impossible pour les outils non OS (par exemple les navigateurs) de gérer les fichiers conformément à la norme POSIX (ou à toute norme de niveau OS).

Par conséquent, nous pouvons être relativement confiants qu'EOL chez EOF n'aura pratiquement aucun impact négatif au niveau de l'application, peu importe s'il s'exécute sur un système d'exploitation UNIX.

À ce stade, nous pouvons affirmer avec certitude que sauter EOL à EOF est sûr lorsque vous traitez avec JS, HTML, CSS côté client. En fait, nous pouvons affirmer que la réduction de l'un de ces fichiers, ne contenant pas de <newline>, est sûre.

Nous pouvons aller un peu plus loin et dire qu'en ce qui concerne NodeJS, il ne peut pas non plus adhérer au standard POSIX étant donné qu'il peut fonctionner dans des environnements non conformes à POSIX.

Que nous reste-t-il alors? Outillage au niveau du système.

Cela signifie que les seuls problèmes qui peuvent survenir concernent les outils qui s'efforcent d'adhérer leurs fonctionnalités à la sémantique de POSIX (par exemple, la définition d'une ligne comme indiqué dans wc).

Même ainsi, tous les shells n'adhéreront pas automatiquement à POSIX. Par exemple, Bash n'a pas par défaut le comportement POSIX. Il y a un interrupteur pour lui permettre: POSIXLY_CORRECT.

Matière à réflexion sur la valeur de l'EOL étant <newline>: https://www.rfc-editor.org/old/EOLstory.txt

En restant sur la piste de l'outillage, à toutes fins pratiques, considérons ceci:

Travaillons avec un fichier qui n'a pas de fin de vie. À ce jour, le fichier dans cet exemple est un JavaScript minifié sans 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

Notez que la cattaille du fichier est exactement la somme de ses parties individuelles. Si la concaténation des fichiers JavaScript est une préoccupation pour les fichiers JS, la préoccupation la plus appropriée serait de démarrer chaque fichier JavaScript avec un point-virgule.

Comme quelqu'un d'autre l'a mentionné dans ce fil: que faire si vous voulez catdeux fichiers dont la sortie ne devient qu'une ligne au lieu de deux? En d'autres termes, catfait ce qu'il est censé faire.

Le mande catne mentionne que la lecture des entrées jusqu'à EOF, pas <newline>. Notez que le -nbasculement de catimprimera également une ligne non terminée (nouvelle ligne) (ou ligne incomplète ) en tant que ligne - étant donné que le décompte commence à 1 (selon le man.)

-n Numéroter les lignes de sortie, en commençant à 1.

Maintenant que nous comprenons comment POSIX définit une ligne , ce comportement devient ambigu, ou vraiment non conforme.

La compréhension de l'objectif et de la conformité d'un outil donné aidera à déterminer à quel point il est essentiel de terminer les fichiers avec une fin de vie. En C, C ++, Java (JAR), etc ... certaines normes imposent une nouvelle ligne pour la validité - aucune norme de ce type n'existe pour JS, HTML, CSS.

Par exemple, au lieu d'en utiliser wc -l filenameun, vous pouvez le faire awk '{x++}END{ print x}' filename, et soyez assuré que le succès de la tâche n'est pas compromis par un fichier que nous pourrions vouloir traiter que nous n'avons pas écrit (par exemple une bibliothèque tierce telle que le JS minifié que nous avons curl) - à moins que notre l'intention était vraiment de compter les lignes au sens conforme POSIX.

Conclusion

Il y aura très peu de cas d'utilisation réels où sauter EOL à EOF pour certains fichiers texte tels que JS, HTML et CSS aura un impact négatif - voire pas du tout. Si nous comptons sur la présence de <newline>, nous limitons la fiabilité de nos outils uniquement aux fichiers que nous créons et nous nous exposons aux erreurs potentielles introduites par des fichiers tiers.

Morale de l'histoire: des outils d'ingénieur qui n'ont pas la faiblesse de s'appuyer sur EOL chez EOF.

N'hésitez pas à publier des cas d'utilisation tels qu'ils s'appliquent à JS, HTML et CSS où nous pouvons examiner comment le fait de sauter EOL a un effet négatif.

Milan Adamovsky
la source
2
POSIX n'est pas tagué dans la question ... wat sur les fins de ligne MVS / OS? ou fins de ligne MS-DOS? Soit dit en passant, tous les systèmes posix connus autorisent les fichiers texte sans terminaison de ligne finale (aucun cas trouvé d'un système de réclamation conforme posix sur lequel "fichier texte" a un traitement spécial dans le noyau pour insérer une nouvelle ligne appropriée au cas où il n'aurait pas it)
Luis Colorado
62

Cela peut être lié à la différence entre :

  • fichier texte (chaque ligne est censée se terminer par une fin de ligne)
  • fichier binaire (il n'y a pas vraiment de "lignes" à proprement parler, et la longueur du fichier doit être préservée)

Si chaque ligne se termine par une fin de ligne, cela évite, par exemple, que la concaténation de deux fichiers texte transforme la dernière ligne de la première ligne en première ligne de la seconde.

De plus, un éditeur peut vérifier à la charge si le fichier se termine en fin de ligne, l'enregistre dans son option locale «eol» et l'utilise lors de l'écriture du fichier.

Il y a quelques années (2005), de nombreux éditeurs (ZDE, Eclipse, Scite, ...) ont "oublié" cette EOL finale, qui n'était pas très appréciée .
Non seulement cela, mais ils ont mal interprété cette fin de vie finale, comme «commencer une nouvelle ligne», et ont commencé à afficher une autre ligne comme si elle existait déjà.
Cela était très visible avec un fichier texte «approprié» avec un éditeur de texte bien comporté comme vim, par rapport à l'ouvrir dans l'un des éditeurs ci-dessus. Il a affiché une ligne supplémentaire en dessous de la dernière ligne réelle du fichier. Vous voyez quelque chose comme ça:

1 first line
2 middle line
3 last line
4
VonC
la source
11
+1. J'ai trouvé cette question SO tout en rencontrant ce problème. C'est très ennuyeux pour Eclipse de montrer cette "fausse" dernière ligne, et si je la supprime, alors git (et tous les autres outils Unix qui attendent EOL) se plaignent. Notez également que ce n'est pas seulement en 2005: Eclipse 4.2 Juno a toujours ce problème.
MestreLion
@MestreLion, Continuation at stackoverflow.com/questions/729692/…
Pacerier
46

Certains outils s'y attendent. Par exemple, wcattend cela:

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1
Flimm
la source
22
Je ne dirais pas "certains", je dis que la plupart des outils s'attendent à ça pour les fichiers texte, sinon tous. cat, git, diff, wc, grep, sed ... la liste est énorme
MestreLion
On pourrait peut-être dire que wccela ne s’attend pas à cela, dans la mesure où cela fonctionne simplement dans la définition POSIX d’une "ligne" par opposition à la compréhension intuitive de la "ligne" par la plupart des gens.
Guildenstern
@Guildenstern La définition intuitive serait wc -ld'imprimer 1dans les deux cas, mais certaines personnes pourraient dire que le deuxième cas devrait s'imprimer 2.
Flimm
@Flimm Si vous pensez \nà un terminateur de ligne, plutôt qu'à un séparateur de ligne, comme le fait POSIX / UNIX, alors attendre le deuxième cas pour imprimer 2 est absolument fou.
point
21

Fondamentalement, il existe de nombreux programmes qui ne traiteront pas les fichiers correctement s'ils n'obtiennent pas le EOL EOF final.

GCC vous en avertit car il fait partie de la norme C. (section 5.1.1.2 apparemment)

Avertissement du compilateur "Pas de nouvelle ligne à la fin du fichier"

cgp
la source
5
GCC n'est pas incapable de traiter le fichier, il doit donner l'avertissement dans le cadre de la norme C.
Bill the Lizard
IIRC, MSVC 2005 s'est plaint des fichiers C qui se terminaient par des lignes incomplètes et a peut-être refusé de les compiler.
Mark K Cowan,
16

Cela remonte aux tout premiers jours où de simples terminaux étaient utilisés. Le caractère de nouvelle ligne a été utilisé pour déclencher un «vidage» des données transférées.

Aujourd'hui, le caractère de nouvelle ligne n'est plus requis. Bien sûr, de nombreuses applications ont toujours des problèmes si la nouvelle ligne n'est pas là, mais je considérerais qu'il s'agit d'un bogue dans ces applications.

Si toutefois vous avez un format de fichier texte où vous avez besoin de la nouvelle ligne, vous obtenez une vérification des données simple très bon marché: si le fichier se termine par une ligne qui n'a pas de nouvelle ligne à la fin, vous savez que le fichier est cassé. Avec un seul octet supplémentaire pour chaque ligne, vous pouvez détecter les fichiers cassés avec une grande précision et presque pas de temps CPU.

Stefan
la source
15
de nos jours, la nouvelle ligne à l'EOF pour les fichiers texte n'est peut-être pas une exigence, mais c'est une convention utile qui fait fonctionner la plupart des outils Unix avec des résultats cohérents. Ce n'est pas du tout un bug.
MestreLion
14
Beaucoup d'entre nous n'utilisent pas du tout les outils Unix, et cela nous est égal.
DaveWalley
12
Ce ne sont pas seulement des outils Unix, n'importe quel outil fonctionnera mieux et / ou sera codé plus simplement s'il peut prendre des formats de fichier raisonnables.
Sam Watkins
2
@Sam Watkins Convenir d'avoir des formats simples et bien définis est une bonne chose . Pourtant, le code doit encore être vérifié et ne pas supposer que les données sont conformes au format.
chux
8
@MestreLion Il s'agit d'un héritage inutile d'un ensemble de mauvais outils conformes à des normes stupides. Ces artefacts de programmation extrémiste (c'est-à-dire tout le fichier! Tout devrait parler du texte brut!) Ne sont pas morts peu de temps après leur invention car ils étaient les seuls outils disponibles du genre à un certain moment de l'histoire. C a été remplacé par C ++, il ne fait pas partie de POSIX, il ne nécessite aucun EOL à EOF, et son utilisation est (évidemment) déconseillée par les luddists * nix.
polkovnikov.ph
14

Un cas d'utilisation distinct: lorsque votre fichier texte est contrôlé par version (dans ce cas spécifiquement sous git bien qu'il s'applique également aux autres). Si du contenu est ajouté à la fin du fichier, la ligne qui était auparavant la dernière ligne aura été modifiée pour inclure un caractère de nouvelle ligne. Cela signifie que blamele fait de savoir quand le fichier a été modifié pour la dernière fois affichera l'ajout de texte, et non le commit avant que vous vouliez réellement voir.

Robin Whittleton
la source
1
diff et blame devraient juste être mis à jour pour détecter les "nouvelles lignes" plutôt que les "nouvelles lignes" ( \n). Problème résolu.
Andrew
1
Vous pouvez utiliser la balise -w pour ignorer les modifications d'espaces, mais ce n'est pas la valeur par défaut.
Robin Whittleton
11

En plus des raisons pratiques ci-dessus, cela ne me surprendrait pas si les créateurs d'Unix (Thompson, Ritchie et al.) Ou leurs prédécesseurs Multics se rendaient compte qu'il y avait une raison théorique d'utiliser des terminateurs de ligne plutôt que des séparateurs de ligne: Avec la ligne terminateurs, vous pouvez encoder tous les fichiers de lignes possibles. Avec les séparateurs de lignes, il n'y a pas de différence entre un fichier de zéro lignes et un fichier contenant une seule ligne vide; les deux sont codés comme un fichier contenant zéro caractère.

Donc, les raisons sont:

  1. Parce que c'est ainsi que POSIX le définit.
  2. Parce que certains outils l'attendent ou "se conduisent mal" sans cela. Par exemple, wc -lne comptera pas une "ligne" finale si elle ne se termine pas par une nouvelle ligne.
  3. Parce que c'est simple et pratique. Sous Unix, catça marche et ça marche sans complication. Il copie simplement les octets de chaque fichier, sans aucun besoin d'interprétation. Je ne pense pas qu'il existe un équivalent DOS cat. L'utilisation copy a+b cfinira par fusionner la dernière ligne de fichier aavec la première ligne de fichier b.
  4. Parce qu'un fichier (ou flux) de zéro ligne peut être distingué d'un fichier d'une ligne vide.
jrw32982 prend en charge Monica
la source
11

Je me le demande depuis des années. Mais je suis tombé sur une bonne raison aujourd'hui.

Imaginez un fichier avec un enregistrement sur chaque ligne (ex: un fichier CSV). Et que l'ordinateur écrivait des enregistrements à la fin du fichier. Mais il s'est soudainement écrasé. Gee était la dernière ligne terminée? (pas une bonne situation)

Mais si nous terminons toujours la dernière ligne, nous le saurons (vérifiez simplement si la dernière ligne est terminée). Sinon, nous devrons probablement rejeter la dernière ligne à chaque fois, juste pour être sûr.

symbiote
la source
10

Vraisemblablement simplement que certains codes d'analyse s'attendaient à ce qu'il soit là.

Je ne suis pas sûr de le considérer comme une "règle", et ce n'est certainement pas quelque chose auquel j'adhère religieusement. Le code le plus sensé saura comment analyser le texte (y compris les encodages) ligne par ligne (tout choix de fin de ligne), avec ou sans retour à la ligne sur la dernière ligne.

En effet - si vous terminez avec une nouvelle ligne: y a-t-il (en théorie) une ligne finale vide entre l'EOL et l'EOF? À méditer ...

Marc Gravell
la source
12
Ce n'est pas une règle, c'est une convention: une ligne est quelque chose qui se termine par une fin de ligne . Donc non, il n'y a pas de "ligne finale vide" entre EOL et EOF.
MestreLion
4
@MestreLion: Mais le personnage en question n'est pas nommé "fin de ligne", il est nommé "retour à la ligne" et / ou "saut de ligne". Un séparateur de ligne, pas un terminateur de ligne. Et le résultat EST une dernière ligne vide.
Ben Voigt
2
Aucun outil (sain) ne compterait le dernier EOL (CR, LF, etc.) d'un fichier comme une ligne vide supplémentaire. Et tous les outils POSIX ne compteront pas les derniers caractères d'un fichier comme une ligne s'il n'y a pas de fin EOL. Indépendamment du nom de caractère EOL étant "saut de ligne" ou "retour chariot" (il n'y a pas de caractère nommé "nouvelle ligne"), à toutes fins pratiques, les outils sensés le traitent comme un terminateur de ligne , pas comme un séparateur de ligne .
MestreLion
2
@MestreLion, êtes-vous sûr que le "terminateur de ligne" est sain d'esprit? Prenez quelques non-programmeurs et faites une enquête rapide. Vous réaliserez rapidement que le concept de lignes est plus proche du concept de "séparateurs de lignes". Le concept de "terminateur de ligne" est juste bizarre .
Pacerier
4
@Sahuagin: Ce n'est pas mon avis, c'est ainsi que la norme POSIX définit une ligne. Un fichier vide avec 0 octets a 0 lignes, donc pas EOL, et un fichier à être considéré comme ayant une seule, ligne blanche, il ne nécessite une EOL. Notez également que cela n'est pertinent que si vous souhaitez compter les lignes d'un fichier, car évidemment, tout éditeur vous permettra de "passer" à la ligne suivante (ou à la première), qu'il y ait déjà une fin de vie.
MestreLion
10

Il y a aussi un problème de programmation pratique avec des fichiers manquant de nouvelles lignes à la fin: le readBash intégré (je ne connais pas les autres readimplémentations) ne fonctionne pas comme prévu:

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

Cela imprime seulementfoo ! La raison en est que lorsqu'il readrencontre la dernière ligne, il écrit le contenu $linemais renvoie le code de sortie 1 car il a atteint EOF. Cela rompt la whileboucle, donc nous n'atteignons jamais la echo $linepièce. Si vous souhaitez gérer cette situation, vous devez procéder comme suit:

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

Autrement dit, faites le echosi l' readéchec en raison d'une ligne non vide à la fin du fichier. Naturellement, dans ce cas, il y aura une nouvelle ligne supplémentaire dans la sortie qui n'était pas dans l'entrée.

l0b0
la source
9

Pourquoi les fichiers (texte) devraient-ils se terminer par une nouvelle ligne?

Comme beaucoup l'ont exprimé, car:

  1. De nombreux programmes ne se comportent pas bien ou échouent sans cela.

  2. Même les programmes qui gèrent bien un fichier n'ont pas de fin '\n', la fonctionnalité de l'outil peut ne pas répondre aux attentes de l'utilisateur - ce qui peut ne pas être clair dans ce cas d'angle.

  3. Les programmes interdisent rarement la finale '\n'(je n'en connais pas).


Pourtant, cela soulève la question suivante:

Que doit faire le code sur les fichiers texte sans nouvelle ligne?

  1. Plus important - N'écrivez pas de code qui suppose qu'un fichier texte se termine par une nouvelle ligne . Supposer qu'un fichier est conforme à un format entraîne une corruption des données, des attaques de pirates et des plantages. Exemple:

    // 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. Si la fin finale '\n'est nécessaire, avertissez l'utilisateur de son absence et des mesures prises. IOWs, validez le format du fichier. Remarque: cela peut inclure une limite à la longueur de ligne maximale, le codage des caractères, etc.

  3. Définissez clairement, documentez, la gestion par le code d'une finale manquante '\n'.

  4. Ne générez pas, autant que possible, un fichier sans la fin '\n'.

chux - Réintégrer Monica
la source
4

Il est très tard ici, mais je viens de rencontrer un bogue dans le traitement des fichiers et cela vient du fait que les fichiers ne se terminent pas par une nouvelle ligne vide. Nous traitions des fichiers texte avec sedet sedomettions la dernière ligne de la sortie, ce qui provoquait l'échec de la structure json et l'envoi du reste du processus.

Tout ce que nous faisions était:

Il y a un exemple de fichier qui dit: foo.txtavec du jsoncontenu à l'intérieur.

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

Le fichier a été créé dans la machine à veuves et les scripts de fenêtre traitaient ce fichier à l'aide des commandes PowerShell. Tout bon.

Lorsque nous avons traité le même fichier à l'aide de la sedcommandesed 's|value|newValue|g' foo.txt > foo.txt.tmp

Le fichier nouvellement généré était

[{
    someProp: value
},
{
    someProp: value

et boom, il a échoué le reste des processus en raison du JSON non valide.

Il est donc toujours recommandé de terminer votre fichier avec une nouvelle ligne vide.

Arpit
la source
3

J'avais toujours l'impression que la règle venait du temps où l'analyse d'un fichier sans retour à la ligne était difficile. Autrement dit, vous finiriez par écrire du code où une fin de ligne était définie par le caractère EOL ou EOF. Il était simplement plus simple de supposer qu'une ligne se terminait par EOL.

Cependant, je crois que la règle est dérivée des compilateurs C nécessitant la nouvelle ligne. Et comme indiqué sur l' avertissement du compilateur «Pas de nouvelle ligne à la fin du fichier» , #include n'ajoutera pas de nouvelle ligne.

he_the_great
la source
0

Imaginez que le fichier est en cours de traitement alors qu'il est toujours généré par un autre processus.

Cela pourrait avoir à voir avec ça? Un indicateur qui indique que le fichier est prêt à être traité.

Pippen_001
la source
-4

Personnellement, j'aime les nouvelles lignes à la fin des fichiers de code source.

Il peut avoir son origine avec Linux ou tous les systèmes UNIX d'ailleurs. Je me souviens des erreurs de compilation (gcc si je ne me trompe pas) car les fichiers de code source ne se terminaient pas par une nouvelle ligne vide. Pourquoi a-t-il été fait de cette façon?

Utilisateur
la source
-6

À mon humble avis, c'est une question de style personnel et d'opinion.

Autrefois, je ne mettais pas cette nouvelle ligne. Un caractère enregistré signifie plus de vitesse grâce à ce modem 14,4K.

Plus tard, j'ai mis cette nouvelle ligne pour qu'il soit plus facile de sélectionner la ligne finale en utilisant shift + downarrow.

Torben Gundtofte-Bruun
la source