¿Por qué los archivos de texto deben terminar con una nueva línea?

1470

Supongo que todos aquí están familiarizados con el dicho de que todos los archivos de texto deben terminar con una nueva línea. Hace años que conozco esta "regla", pero siempre me he preguntado: ¿por qué?

Will Robertson
fuente
30
Solo un poco. no es una "nueva línea" al final del archivo. Es un "salto de línea" al final de la última línea. Además, vea la mejor respuesta en una pregunta relacionada: stackoverflow.com/questions/16222530/…
gcb
346
Solo para señalar un poco más, en realidad no escribió "nueva línea", escribió "nueva línea", lo cual es correcto.
sindrenm
55
no estoy familiarizado, pero me pregunto si lo estoy porque la cantidad de casos en los que esa nueva línea superflua realmente está rompiendo las cosas es demasiado alta para mis gustos
tobibeer
2
Actualmente estoy usando secuencias Node.js para analizar datos de texto sin formato línea por línea, y la falta de salto de línea de terminal es molesta, ya que tengo que agregar lógica adicional para cuando el lado de entrada de la secuencia esté terminado / cerrado para garantizar que se procese la última línea.
Mark K Cowan
23
La forma en que Unix considera su comportamiento general al final de los archivos es la siguiente: \ n los caracteres no comienzan líneas; en cambio, los terminan. Entonces, \ n es un terminador de línea, no un separador de línea. La primera línea (como todas las líneas) no necesita \ n para comenzar. La última línea (como todas las líneas) necesita un \ n para finalizarla. Un \ n al final del archivo no crea una línea adicional. A veces, sin embargo, los editores de texto agregarán una línea en blanco visible allí. Incluso emacs lo hace, opcionalmente .
MarkDBlackwell

Respuestas:

1383

Porque así es como el estándar POSIX define una línea :

Línea 3.206
Una secuencia de cero o más caracteres que no son <newline> más un carácter <newline> que termina.

Por lo tanto, las líneas que no terminan en un carácter de nueva línea no se consideran líneas reales. Es por eso que algunos programas tienen problemas para procesar la última línea de un archivo si no se termina la nueva línea.

Hay al menos una gran ventaja de esta guía cuando se trabaja en un emulador de terminal: todas las herramientas de Unix esperan esta convención y funcionan con ella. Por ejemplo, al concatenar archivos con cat, un archivo terminado por nueva línea tendrá un efecto diferente que uno sin:

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

Y, como el ejemplo anterior también demuestra, cuando se muestra el archivo en la línea de comando (por ejemplo, a través de more), un archivo terminado en nueva línea da como resultado una visualización correcta. Un archivo terminado incorrectamente puede ser ilegible (segunda línea).

Para mantener la coherencia, es muy útil seguir esta regla; de lo contrario, se generará un trabajo adicional al tratar con las herramientas predeterminadas de Unix.


Piénselo de manera diferente: si las líneas no terminan con nueva línea, hacer comandos como catútiles es mucho más difícil: ¿cómo se hace un comando para concatenar archivos de manera que

  1. coloca el inicio de cada archivo en una nueva línea, que es lo que desea el 95% del tiempo; pero
  2. permite fusionar la última y la primera línea de dos archivos, como en el ejemplo anterior entre b.txty c.txt?

Por supuesto, esto es solucionable, pero necesita hacer que el uso sea catmás complejo (agregando argumentos de línea de comando posicional, por ejemplo cat a.txt --no-newline b.txt c.txt), y ahora el comando en lugar de cada archivo individual controla cómo se pega junto con otros archivos. Esto es casi seguro que no es conveniente.

... O necesita introducir un carácter centinela especial para marcar una línea que se supone que debe continuar en lugar de terminar. Bueno, ahora está atrapado en la misma situación que en POSIX, excepto invertido (carácter de continuación de línea en lugar de carácter de terminación de línea).


Ahora, en los sistemas que no son compatibles con POSIX (hoy en día es principalmente Windows), el punto es discutible: los archivos generalmente no terminan en una nueva línea, y la definición (informal) de una línea podría ser, por ejemplo, "texto separado por nuevas líneas" (tenga en cuenta el énfasis). Esto es completamente válido. Sin embargo, para los datos estructurados (por ejemplo, el código de programación) hace que el análisis sea mínimamente más complicado: generalmente significa que los analizadores tienen que ser reescritos. Si un analizador se escribió originalmente con la definición POSIX en mente, entonces podría ser más fácil modificar la secuencia de tokens en lugar del analizador; en otras palabras, agregue un token de "nueva línea artificial" al final de la entrada.

Konrad Rudolph
fuente
99
Aunque ahora es poco práctico rectificar, claramente POSIX cometió un error al definir la línea, como evidencia por la cantidad de preguntas relacionadas con este tema. Una línea debería haberse definido como cero o más caracteres terminados en <eol>, <eof> o <eol> <eof>. La complejidad del analizador no es una preocupación válida. La complejidad, siempre que sea posible, debe trasladarse de la cabeza del programador a la biblioteca.
Doug Coburn
23
@DougCoburn Esta respuesta solía tener una discusión técnica exhaustiva que explica por qué esto está mal y por qué POSIX hizo lo correcto. Lamentablemente, estos comentarios fueron eliminados recientemente por un moderador demasiado entusiasta. Brevemente, no se trata de analizar la complejidad; más bien, su definición hace que sea mucho más difícil crear herramientas, como catde una manera que sea útil y consistente.
Konrad Rudolph el
8
@Leon La regla POSIX se trata de reducir los casos extremos. Y lo hace muy bien. De hecho, no sé cómo la gente no comprende esto: es la definición más simple y coherente posible de una línea.
Konrad Rudolph
66
@BT Creo que está asumiendo que mi ejemplo de un flujo de trabajo más conveniente es la razón detrás de la decisión. No es, es solo una consecuencia. La razón es que la regla POSIX es la regla más simple y que hace que el manejo de líneas en un analizador sea el más fácil. La única razón por la que incluso estamos teniendo el debate es que Windows lo hace de manera diferente y que, como consecuencia, hay numerosas herramientas que fallan en los archivos POSIX. Si todos hicieran POSIX, no habría ningún problema. Sin embargo, la gente se queja de POSIX, no de Windows.
Konrad Rudolph
77
@BT Solo me refiero a Windows para señalar los casos en los que las reglas POSIX no tienen sentido (en otras palabras, te estaba tirando un hueso). Estoy más que feliz de no volver a mencionarlo en esta discusión. Pero entonces su reclamo tiene aún menos sentido: en las plataformas POSIX simplemente no tiene sentido discutir archivos de texto con diferentes convenciones de final de línea, porque no hay razón para producirlos. Cual es la ventaja? Literalmente no hay ninguno. - En resumen, realmente no entiendo el odio que esta respuesta (o la regla POSIX) está engendrando. Para ser sincero, es completamente irracional.
Konrad Rudolph
282

Cada línea debe terminar en un carácter de nueva línea, incluida la última. Algunos programas tienen problemas para procesar la última línea de un archivo si no se termina la nueva línea.

GCC lo advierte no porque no pueda procesar el archivo, sino porque debe hacerlo como parte del estándar.

El estándar del lenguaje C dice que un archivo fuente que no está vacío terminará en un carácter de nueva línea, que no estará precedido inmediatamente por un carácter de barra diagonal inversa.

Como se trata de una cláusula "deberá", debemos emitir un mensaje de diagnóstico por una violación de esta regla.

Esto se encuentra en la sección 2.1.1.2 del estándar ANSI C 1989. Sección 5.1.1.2 de la norma ISO C 1999 (y probablemente también la norma ISO C 1990).

Referencia: El archivo de correo GCC / GNU .

Bill el lagarto
fuente
17
por favor escriba buenos programas que permitan insertar esa nueva línea donde sea necesario durante el procesamiento o puedan manejar adecuadamente los "faltantes" ... que, de hecho, no faltan
tobibeer
44
@BilltheLizard, ¿Cuáles son algunos ejemplos de "Algunos programas tienen problemas para procesar la última línea de un archivo si no se ha terminado la nueva línea" ?
Pacerier
44
@Pacerier wc -lno contará la última línea de un archivo si no se termina la nueva línea. Además, catunirá la última línea de un archivo con la primera línea del siguiente archivo en una sola si la última línea del primer archivo no tiene una nueva línea terminada. Casi cualquier programa que busque nuevas líneas como delimitador tiene el potencial de estropear esto.
Bill the Lizard
2
@BilltheLizard, me refiero wcha sido ya mencionado ....
Pacerier
2
@BilltheLizard, My bad, para aclarar: ¿cuáles son algunos ejemplos de programas que tienen problemas para procesar la última línea de un archivo si no está terminado de nueva línea (además de los que ya se han mencionado en masa en el hilo como caty wc)?
Pacerier
116

Esta respuesta es un intento de una respuesta técnica en lugar de una opinión.

Si queremos ser puristas de POSIX, definimos una línea como:

Una secuencia de cero o más caracteres que no son <newline> más un carácter <newline> que termina.

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

Una línea incompleta como:

Una secuencia de uno o más caracteres que no son <newline> al final del archivo.

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

Un archivo de texto como:

Un archivo que contiene caracteres organizados en cero o más líneas. Las líneas no contienen caracteres NUL y ninguno puede exceder {LINE_MAX} bytes de longitud, incluido el carácter <newline>. Aunque POSIX.1-2008 no distingue entre archivos de texto y archivos binarios (consulte el estándar ISO C), muchas utilidades solo producen resultados predecibles o significativos cuando operan en archivos de texto. Las utilidades estándar que tienen tales restricciones siempre especifican "archivos de texto" en sus secciones STDIN o INPUT FILES.

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

Una cadena como:

Una secuencia contigua de bytes terminados por e incluyendo el primer byte nulo.

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

A partir de esto, podemos deducir que la única vez que potencialmente encontraremos algún tipo de problema es si tratamos con el concepto de una línea de un archivo o un archivo como un archivo de texto (ya que un archivo de texto es una organización de cero o más líneas, y una línea que conocemos debe terminar con una <nueva línea>).

El caso en cuestión: wc -l filename.

Del wcmanual de 'leemos:

Una línea se define como una cadena de caracteres delimitada por un carácter <línea nueva>.

¿Cuáles son las implicaciones para los archivos JavaScript, HTML y CSS, ya que son archivos de texto ?

En los navegadores, IDEs modernos y otras aplicaciones front-end no hay problemas para omitir EOL en EOF. Las aplicaciones analizarán los archivos correctamente. Tiene que hacerlo ya que no todos los sistemas operativos cumplen con el estándar POSIX, por lo que no sería práctico que las herramientas que no sean OS (por ejemplo, navegadores) manejen archivos de acuerdo con el estándar POSIX (o cualquier estándar de nivel OS).

Como resultado, podemos estar relativamente seguros de que EOL en EOF prácticamente no tendrá un impacto negativo a nivel de aplicación, independientemente de si se está ejecutando en un sistema operativo UNIX.

En este punto, podemos decir con confianza que omitir EOL en EOF es seguro cuando se trata de JS, HTML, CSS en el lado del cliente. En realidad, podemos afirmar que es seguro minificar cualquiera de estos archivos, que no contengan <newline>.

Podemos ir un paso más allá y decir que, en lo que respecta a NodeJS, tampoco puede adherirse al estándar POSIX, ya que puede ejecutarse en entornos no compatibles con POSIX.

¿Qué nos queda entonces? Sistema de herramientas a nivel.

Esto significa que los únicos problemas que pueden surgir son las herramientas que hacen un esfuerzo por adherir su funcionalidad a la semántica de POSIX (por ejemplo, la definición de una línea como se muestra en la figura wc).

Aun así, no todos los shells se adherirán automáticamente a POSIX. Bash, por ejemplo, no tiene el comportamiento POSIX predeterminado. Hay un interruptor que le permita: POSIXLY_CORRECT.

Alimento para reflexionar sobre el valor de EOL <newline>: https://www.rfc-editor.org/old/EOLstory.txt

Mantenerse en la pista de herramientas, para todos los propósitos prácticos, consideremos esto:

Trabajemos con un archivo que no tiene EOL. Al momento de escribir esto, el archivo en este ejemplo es un JavaScript minimizado sin 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

Observe que el cattamaño del archivo es exactamente la suma de sus partes individuales. Si la concatenación de archivos JavaScript es una preocupación para los archivos JS, la preocupación más apropiada sería comenzar cada archivo JavaScript con un punto y coma.

Como alguien más mencionó en este hilo: ¿qué catpasa si desea dos archivos cuya salida se convierte en una sola línea en lugar de dos? En otras palabras, cathace lo que se supone que debe hacer.

El mande catsólo menciona la lectura de entrada hasta EOF, no <nueva línea>. Tenga en cuenta que el -ncambio de cattambién imprimirá una línea terminada no <newline> (o línea incompleta ) como una línea , ya que el recuento comienza en 1 (de acuerdo con el man.)

-n Numera las líneas de salida, comenzando en 1.

Ahora que entendemos cómo POSIX define una línea , este comportamiento se vuelve ambiguo o realmente no conforme.

Comprender el propósito y el cumplimiento de una herramienta determinada ayudará a determinar qué tan importante es finalizar los archivos con una EOL. En C, C ++, Java (JAR), etc., algunos estándares dictarán una nueva línea de validez; no existe dicho estándar para JS, HTML, CSS.

Por ejemplo, en lugar de usar wc -l filenameuno podría hacerlo awk '{x++}END{ print x}' filename, y puede estar seguro de que el éxito de la tarea no se ve comprometido por un archivo que queremos procesar que no escribimos (por ejemplo, una biblioteca de terceros como el JS minificado que curld), a menos que nuestro la intención era realmente contar líneas en el sentido compatible con POSIX.

Conclusión

Habrá muy pocos casos de uso de la vida real en los que omitir EOL en EOF para ciertos archivos de texto como JS, HTML y CSS tendrá un impacto negativo, si es que lo tiene. Si confiamos en que <newline> esté presente, estamos restringiendo la confiabilidad de nuestras herramientas solo a los archivos que creamos y nos abrimos a posibles errores introducidos por archivos de terceros.

Moraleja de la historia: herramientas de ingeniería que no tienen la debilidad de confiar en EOL en EOF.

No dude en publicar casos de uso, ya que se aplican a JS, HTML y CSS, donde podemos examinar cómo omitir EOL tiene un efecto adverso.

Milan Adamovsky
fuente
2
POSIX no está etiquetado en la pregunta ... ¿qué hay de las terminaciones de línea MVS / OS? o finales de línea MS-DOS? Por cierto, todos los sistemas posix conocidos permiten archivos de texto sin un final de línea final (no se encontró ningún caso de un sistema de reclamo compatible con posix en el que el "archivo de texto" tenga un tratamiento especial en el núcleo para insertar una nueva línea adecuada en caso de que no tenga it)
Luis Colorado
62

Puede estar relacionado con la diferencia entre :

  • archivo de texto (se supone que cada línea termina en un final de línea)
  • archivo binario (no hay verdaderas "líneas" para hablar, y la longitud del archivo debe ser preservada)

Si cada línea termina en un final de línea, esto evita, por ejemplo, que la concatenación de dos archivos de texto haría que la última línea de la primera ejecución se convirtiera en la primera línea de la segunda.

Además, un editor puede verificar en la carga si el archivo termina en un final de línea, lo guarda en su opción local 'eol' y lo usa al escribir el archivo.

Hace unos años (2005), muchos editores (ZDE, Eclipse, Scite, ...) "olvidaron" esa EOL final, que no fue muy apreciada .
No solo eso, sino que interpretaron esa EOL final de manera incorrecta, como 'comenzar una nueva línea', y en realidad comienzan a mostrar otra línea como si ya existiera.
Esto era muy visible con un archivo de texto 'adecuado' con un editor de texto con buen comportamiento como vim, en comparación con abrirlo en uno de los editores anteriores. Mostraba una línea extra debajo de la última línea real del archivo. Ves algo como esto:

1 first line
2 middle line
3 last line
4
VonC
fuente
11
+1. Encontré esta pregunta SO mientras experimentaba este mismo problema. Es muy molesto para Eclipse mostrar esta última línea "falsa", y si la elimino, se queja git (y todas las demás herramientas de Unix que esperan EOL). Además, tenga en cuenta que esto no es solo en 2005: Eclipse 4.2 Juno todavía tiene este problema.
MestreLion
@MestreLion, Continuación en stackoverflow.com/questions/729692/…
Pacerier
46

Algunas herramientas esperan esto. Por ejemplo, wcespera esto:

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1
Flimm
fuente
22
No diría "algunos", digo que la mayoría de las herramientas esperan eso para archivos de texto, si no todos. cat, git, diff, wc, grep, sed ... la lista es enorme
MestreLion
Tal vez se podría decir que wcno espera esto, ya que simplemente está trabajando dentro de la definición POSIX de una "línea" en lugar de la comprensión intuitiva de la "línea" de la mayoría de las personas.
Guildenstern
@Guildenstern La definición intuitiva sería para wc -limprimir 1en ambos casos, pero algunas personas podrían decir que el segundo caso debería imprimir 2.
Flimm
@Flimm Si piensa \nen un terminador de línea, en lugar de un separador de línea, como lo hace POSIX / UNIX, entonces esperar que el segundo caso imprima 2 es absolutamente una locura.
punto
21

Básicamente, hay muchos programas que no procesarán los archivos correctamente si no obtienen el EOL EOF final.

GCC le advierte sobre esto porque se espera como parte del estándar C. (sección 5.1.1.2 aparentemente)

Advertencia del compilador "No hay nueva línea al final del archivo"

cgp
fuente
55
GCC no es incapaz de procesar el archivo, tiene que dar la advertencia como parte del estándar C.
Bill the Lizard
IIRC, MSVC 2005 se quejó de archivos C que terminaron con líneas incompletas y posiblemente se negaron a compilarlos.
Mark K Cowan
16

Esto se origina desde los primeros días cuando se usaban terminales simples. El carácter de nueva línea se utilizó para desencadenar un 'vaciado' de los datos transferidos.

Hoy, el carácter de nueva línea ya no es necesario. Claro, muchas aplicaciones todavía tienen problemas si la nueva línea no está allí, pero lo consideraría un error en esas aplicaciones.

Sin embargo, si tiene un formato de archivo de texto en el que necesita la nueva línea, obtendrá una verificación de datos simple muy barata: si el archivo termina con una línea que no tiene una nueva línea al final, sabe que el archivo está roto. Con solo un byte adicional para cada línea, puede detectar archivos rotos con alta precisión y casi sin tiempo de CPU.

Stefan
fuente
15
Hoy en día, la nueva línea en EOF para archivos de texto puede no ser un requisito, pero es una convención útil que hace que la mayoría de las herramientas de Unix funcionen juntas con resultados consistentes. No es un error en absoluto.
MestreLion
14
Muchos de nosotros no utilizamos las herramientas de Unix, y no nos importa.
DaveWalley
12
No son solo herramientas Unix, cualquier herramienta funcionará mejor y / o se codificará de manera más simple si puede asumir formatos de archivo sensibles.
Sam Watkins, el
2
@Sam Watkins Estoy de acuerdo en que tener formatos simples y bien definidos es bueno. Sin embargo, el código aún necesita verificar y no suponer que los datos cumplen con el formato.
chux - Restablecer Monica
8
@MestreLion Este es un legado inútil de un conjunto de herramientas malas que cumplen con los estándares estúpidos. Estos artefactos de la programación extremista (es decir, ¡todo el archivo! ¡Todo debería hablar en texto plano!) No murieron poco después de su invención porque eran las únicas herramientas disponibles de este tipo en un momento determinado de la historia. C ++ fue reemplazado por C ++, no es parte de POSIX, no requiere EOL en EOF, y su uso es (obviamente) desaconsejado por * nix luddists.
polkovnikov.ph
14

Un caso de uso separado: cuando su archivo de texto está controlado por la versión (en este caso específicamente bajo git, aunque también se aplica a otros). Si se agrega contenido al final del archivo, la línea que anteriormente era la última línea se habrá editado para incluir un carácter de nueva línea. Esto significa que blameal buscar el archivo para saber cuándo se editó esa línea por última vez, se mostrará la adición de texto, no la confirmación antes de lo que realmente quería ver.

Robin Whittleton
fuente
1
diff y blame solo deben actualizarse para detectar "nuevas líneas" en lugar de "nuevas líneas" ( \n). Problema resuelto.
Andrew
1
Puede usar la etiqueta -w para ignorar los cambios en los espacios en blanco, pero no son los predeterminados.
Robin Whittleton
11

Además de las razones prácticas anteriores, no me sorprendería si los creadores de Unix (Thompson, Ritchie, et al.) O sus predecesores Multics se dieran cuenta de que hay una razón teórica para usar terminadores de línea en lugar de separadores de línea: con línea terminadores, puede codificar todos los archivos de líneas posibles. Con los separadores de línea, no hay diferencia entre un archivo de líneas cero y un archivo que contiene una sola línea vacía; ambos están codificados como un archivo que contiene cero caracteres.

Entonces, las razones son:

  1. Porque esa es la forma en que POSIX lo define.
  2. Porque algunas herramientas lo esperan o "se portan mal" sin él. Por ejemplo, wc -lno contará una "línea" final si no termina con una nueva línea.
  3. Porque es simple y conveniente. En Unix, catsimplemente funciona y funciona sin complicaciones. Simplemente copia los bytes de cada archivo, sin necesidad de interpretación. No creo que haya un DOS equivalente a cat. El uso copy a+b cterminará fusionando la última línea de archivo acon la primera línea de archivo b.
  4. Porque un archivo (o secuencia) de líneas cero se puede distinguir de un archivo de una línea vacía.
jrw32982 es compatible con Monica
fuente
11

Me lo he preguntado por años. Pero me encontré con una buena razón hoy.

Imagine un archivo con un registro en cada línea (por ejemplo, un archivo CSV). Y que la computadora estaba escribiendo registros al final del archivo. Pero de repente se estrelló. Gee fue la última línea completa? (no es una buena situación)

Pero si siempre terminamos la última línea, entonces sabríamos (simplemente verifique si la última línea está terminada). De lo contrario, probablemente tendríamos que descartar la última línea cada vez, solo para estar seguros.

simbionte
fuente
10

Presumiblemente simplemente que algún código de análisis esperaba que estuviera allí.

No estoy seguro de considerarlo una "regla", y ciertamente no es algo a lo que me adhiera religiosamente. El código más sensible sabrá cómo analizar el texto (incluidas las codificaciones) línea por línea (cualquier elección de terminaciones de línea), con o sin una nueva línea en la última línea.

De hecho, si termina con una nueva línea: ¿hay (en teoría) una línea final vacía entre la EOL y la EOF? Uno para reflexionar ...

Marc Gravell
fuente
12
No es una regla, es una convención: una línea es algo que termina con un final de línea . Entonces no, no hay una "línea final vacía" entre EOL y EOF.
MestreLion
44
@MestreLion: Pero el personaje en cuestión no se llama "fin de línea", se llama "nueva línea" y / o "salto de línea". Un separador de línea, no un terminador de línea. Y el resultado ES una línea vacía final.
Ben Voigt
2
Ninguna herramienta (sana) contaría la última EOL (CR, LF, etc.) de un archivo como una línea vacía adicional. Y todas las herramientas POSIX no contarán los últimos caracteres de un archivo como una línea si no hay EOL final. Independientemente de que el nombre del carácter EOL sea ​​"avance de línea" o "retorno de carro" (no hay ningún carácter llamado "nueva línea"), para todas las prácticas, las herramientas sensibles lo tratan como un terminador de línea , no como un separador de línea .
MestreLion
2
@MestreLion, ¿estás seguro de que el "terminador de línea" está cuerdo? Tome algunos no programadores y haga una encuesta rápida. Rápidamente se dará cuenta de que el concepto de líneas está más cerca del concepto de "separadores de línea". El concepto de "terminador de línea" es simplemente extraño .
Pacerier
44
@Sahuagin: Esta no es mi opinión, así es como el Estándar POSIX define una línea. Un archivo vacío con 0 bytes tiene 0 líneas, por lo tanto, sin EOL, y un archivo que se considera que tiene una única línea, en blanco, se hace requerir una EOL. También tenga en cuenta que esto solo es relevante si desea contar las líneas en un archivo, ya que obviamente cualquier editor le permitirá "llegar" a la siguiente (o la primera) línea independientemente de si ya hay una EOL allí.
MestreLion
10

También hay un problema práctico de programación con archivos que carecen de nuevas líneas al final: el readBash incorporado (no sé sobre otras readimplementaciones) no funciona como se esperaba:

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

¡Esto solo sefoo imprime ! La razón es que cuando readencuentra la última línea, escribe el contenido $linepero devuelve el código de salida 1 porque llegó a EOF. Esto rompe el whileciclo, por lo que nunca llegamos a la echo $lineparte. Si desea manejar esta situación, debe hacer lo siguiente:

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

Es decir, haga el echosi readfalló debido a una línea no vacía al final del archivo. Naturalmente, en este caso habrá una nueva línea adicional en la salida que no estaba en la entrada.

l0b0
fuente
9

¿Por qué los archivos (de texto) deben terminar con una nueva línea?

Como bien expresado por muchos, porque:

  1. Muchos programas no se comportan bien o fallan sin él.

  2. Incluso los programas que manejan bien un archivo carecen de un final '\n', la funcionalidad de la herramienta puede no cumplir con las expectativas del usuario, lo que puede no estar claro en este caso de esquina.

  3. Los programas rara vez rechazan el final '\n'(no sé de ninguno).


Sin embargo, esto plantea la siguiente pregunta:

¿Qué debe hacer el código sobre los archivos de texto sin una nueva línea?

  1. Lo más importante: no escriba código que suponga que un archivo de texto termina con una nueva línea . Asumir que un archivo se ajusta a un formato conduce a la corrupción de datos, ataques de piratas informáticos y bloqueos. Ejemplo:

    // 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 '\n'se necesita el seguimiento final , alertar al usuario sobre su ausencia y la acción tomada. IOW, valide el formato del archivo. Nota: Esto puede incluir un límite a la longitud máxima de línea, codificación de caracteres, etc.

  3. Definir claramente, documentar, el manejo del código de un final faltante '\n'.

  4. No, como sea posible, genere un archivo que carece del final '\n'.

chux - Restablece a Monica
fuente
4

Es muy tarde aquí, pero me enfrenté a un error en el procesamiento de archivos y eso ocurrió porque los archivos no terminaban con una nueva línea vacía. Estábamos procesando archivos de texto sedy sedomitimos la última línea de la salida, lo que causaba una estructura json no válida y enviaba el resto del proceso a un estado fallido.

Todo lo que estábamos haciendo era:

Hay un archivo de muestra que dice: foo.txtcon algún jsoncontenido dentro.

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

El archivo fue creado en la máquina de viudas y las secuencias de comandos de la ventana procesaban ese archivo usando los comandos de PowerShell. Todo bien.

Cuando procesamos el mismo archivo usando el sedcomandosed 's|value|newValue|g' foo.txt > foo.txt.tmp

El archivo recién generado fue

[{
    someProp: value
},
{
    someProp: value

y boom, falló el resto de los procesos debido al JSON inválido.

Por lo tanto, siempre es una buena práctica finalizar su archivo con una nueva línea vacía.

Arpit
fuente
3

Siempre tuve la impresión de que la regla venía de cuando era difícil analizar un archivo sin una nueva línea final. Es decir, terminaría escribiendo código donde el final de línea fue definido por el carácter EOL o EOF. Era más simple asumir que una línea terminaba con EOL.

Sin embargo, creo que la regla se deriva de los compiladores de C que requieren la nueva línea. Y como se señaló en la advertencia del compilador "No hay nueva línea al final del archivo" , #include no agregará una nueva línea.

he_the_great
fuente
0

Imagine que el archivo se está procesando mientras el archivo sigue siendo generado por otro proceso.

¿Podría tener que ver con eso? Una bandera que indica que el archivo está listo para ser procesado.

Pippen_001
fuente
-4

Personalmente, me gustan las nuevas líneas al final de los archivos de código fuente.

Puede tener su origen con Linux o todos los sistemas UNIX para el caso. Recuerdo que hubo errores de compilación (gcc si no me equivoco) porque los archivos de código fuente no terminaron con una nueva línea vacía. ¿Por qué se hizo de esta manera? Uno debe preguntarse.

Usuario
fuente
-6

En mi humilde opinión, es una cuestión de estilo personal y opinión.

En los viejos tiempos, no ponía esa nueva línea. Un personaje guardado significa más velocidad a través de ese módem de 14.4K.

Más tarde, puse esa nueva línea para que sea más fácil seleccionar la línea final usando shift + downarrow.

Torben Gundtofte-Bruun
fuente