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


Je suppose que tout le monde ici est familier avec l'adage que tous les fichiers texte devraient se terminer par un saut de ligne. Je connais cette "règle" depuis des années mais je me suis toujours demandé - pourquoi?


1090
2018-04-08 12:16


origine


Réponses:


Parce que c'est comment la norme POSIX définit un ligne:

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

Par conséquent, les lignes ne se terminant pas par un caractère de retour à la 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 pour cette directive lorsque vous travaillez sur un émulateur de terminal: Tous les outils Unix attendent cette convention et fonctionnent avec. Par exemple, lors de la concaténation de fichiers avec cat, un fichier terminé par newline aura un effet différent de celui sans:

$ more a.txt
foo$ more b.txt
bar
$ more c.txt
baz
$ cat *.txt
foobar
baz

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

Par souci de cohérence, il est très utile de suivre cette règle - faire autrement exigera un surcroît de travail avec les outils Unix par défaut.

Maintenant, sur non conforme POSIX (ce qui est principalement Windows), le point est discutable: les fichiers ne se terminent généralement pas par un saut de ligne, et la définition (informelle) d'une ligne peut être par exemple «du texte qui est séparé par newlines "(notez l'emphase). Ceci est entièrement valide. Cependant, pour les données structurées (par exemple le code de programmation), cela rend l'analyse syntaxique plus compliquée: cela signifie généralement que les parseurs doivent être réécrits. Si un analyseur a été écrit à l'origine avec la définition POSIX à l'esprit, il peut être plus facile de modifier le flux de jetons plutôt que l'analyseur. En d'autres termes, ajoutez un jeton "nouvelle ligne artificielle" à la fin de l'entrée.


1021
2018-04-08 12:46



Chaque ligne doit être terminée dans un caractère de nouvelle ligne, y compris le dernier. Certains programmes rencontrent des problèmes lors du traitement de la dernière ligne d'un fichier si ce dernier n'est pas terminé.

GCC met en garde à ce sujet pas parce qu'il ne peut pas traiter le fichier, mais parce qu'il doit dans le cadre de la norme.

La norme de langage C dit   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'un caractère barre oblique inverse.

Comme 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: L'archive de courrier GCC / GNU.


245
2018-04-08 12:26



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

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

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

La source: http://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 <newline> à la fin du fichier.

La source: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195

Un fichier texte en tant que:

Un fichier contenant 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 la longueur de {LINE_MAX} octets, y compris le caractère <nouvelle ligne>. 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 produisent uniquement des résultats prévisibles ou significatifs lors de l'utilisation de fichiers texte. Les utilitaires standard qui ont de telles restrictions spécifient toujours les "fichiers texte" dans leurs sections STDIN ou INPUT FILES.

La source: http://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.

La source: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396

A partir de là, nous pouvons en déduire que la seule fois où nous le ferons potentiellement rencontrer tout type de problèmes sont si nous traitons avec le concept d'un ligne d'un fichier ou d'un fichier en tant que fichier texte (étant un fichier texte est une organisation de zéro ou plusieurs lignes, et une ligne que nous savons doit se terminer avec un <newline>).

Affaire au point: wc -l filename.

Du wcle manuel, nous lisons:

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

Quelles sont les implications pour les fichiers JavaScript, HTML et CSS alors qu'ils sont texte  des dossiers?

Dans les navigateurs, les IDE modernes et d'autres applications frontales, il n'y a aucun problème à ignorer EOL à EOF. Les applications analyseront les fichiers correctement. Comme tous les systèmes d'exploitation ne sont pas conformes à la norme POSIX, il serait peu pratique pour les outils non OS (par exemple les navigateurs) de gérer les fichiers selon la norme POSIX (ou toute norme au niveau du système d'exploitation).

En conséquence, nous pouvons être relativement sûrs que EOL à EOF n'aura pratiquement aucun impact négatif au niveau de l'application - indépendamment du fait qu'il fonctionne sur un système d'exploitation UNIX.

À ce stade, nous pouvons dire avec confiance que sauter EOL à EOF est sûr lorsqu'il s'agit de JS, HTML, CSS sur le côté client. En fait, nous pouvons affirmer que la réduction de l'un de ces fichiers, sans <newline>, est sûre.

Nous pouvons aller plus loin en disant que, pour NodeJS, il ne peut pas non plus adhérer à la norme POSIX car il peut fonctionner dans des environnements non compatibles avec POSIX.

Que restons-nous alors? Outil de niveau système.

Cela signifie que les seuls problèmes qui peuvent survenir sont avec des outils qui font un effort pour faire adhérer leurs fonctionnalités à la sémantique de POSIX (par exemple la définition d'une ligne comme montré dans wc).

Même ainsi, tous les shells n'adhèrent pas automatiquement à POSIX. Bash par exemple n'a pas le comportement POSIX par défaut. Il y a un commutateur pour l'activer: POSIXLY_CORRECT.

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

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

Travaillons avec un fichier qui n'a pas EOL. A 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 le cat la taille du fichier est exactement la somme de ses parties individuelles. Si la concaténation de fichiers JavaScript est un problème pour les fichiers JS, le plus approprié serait de démarrer chaque fichier JavaScript avec un point-virgule.

Comme quelqu'un d'autre mentionné dans ce fil: et si vous voulez cat deux fichiers dont la sortie devient juste une ligne au lieu de deux? En d'autres termes, cat fait ce qu'il est censé faire.

le man de cat mentionne seulement la lecture de l'entrée jusqu'à EOF, pas <newline>. Notez que le -n commutateur de cat imprimera également une ligne non <newline> terminée (ou ligne incomplète) comme un ligne - étant que le compte commence à 1 (selon le man.)

-n Numérote les lignes de sortie à partir de 1.

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

Comprendre le but et 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 (JARs), etc ... certaines normes dicteront une nouvelle ligne pour la validité - aucune norme n'existe pour JS, HTML, CSS.

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

Conclusion

Il y aura très peu de cas d'utilisation dans la vie réelle 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 nous appuyons sur la présence de <newline>, nous limitons la fiabilité de nos outils uniquement aux fichiers que nous créons et nous nous ouvrons à d'éventuelles erreurs introduites par des fichiers tiers.

Morale de l'histoire: Un outillage d'ingénieur qui n'a pas la faiblesse de s'appuyer sur EOL chez EOF.

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


87
2017-08-15 06:31



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

  • fichier texte (chaque ligne est supposée se terminer en fin de ligne)
  • fichier binaire (il n'y a pas de véritables "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 fasse passer la dernière ligne du premier passage dans la première ligne de la seconde.

De plus, un éditeur peut vérifier au chargement 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 rédacteurs (ZDE, Eclipse, Scite, ...) ont "oublié" cette dernière EOL, ce qui n'était pas très apprécié.
Non seulement cela, mais ils ont mal interprété cette fin de liste finale, comme «commencer une nouvelle ligne», et commencer à 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, comparé à l'ouverture 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

59
2018-04-08 12:29



Certains outils attendent cela. Par exemple, wc attend ceci:

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

37
2017-10-12 14:16



Fondamentalement, il existe de nombreux programmes qui ne traiteront pas correctement les fichiers s'ils n'obtiennent pas la version finale EOF EOF.

GCC vous avertit à ce sujet parce que c'est prévu dans le cadre de la norme C. (section 5.1.1.2 apparemment)

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


18
2018-04-08 12:21



Cela provient des tout premiers jours où de simples terminaux ont été utilisés. Le caractère de nouvelle ligne a été utilisé pour déclencher un «flush» 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 encore des problèmes si le retour à la ligne n'est pas là, mais je considérerais que c'est un bug dans ces applications.

Si toutefois vous avez un format de fichier texte où vous exiger la nouvelle ligne, vous obtenez une vérification simple des données 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 seulement un octet supplémentaire pour chaque ligne, vous pouvez détecter les fichiers brisés avec une grande précision et presque pas de temps CPU.


12
2018-04-08 12:41