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é?
file
unix
text-files
newline
Will Robertson
fuente
fuente
Respuestas:
Porque así es como el estándar POSIX define una línea :
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: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 queb.txt
yc.txt
?Por supuesto, esto es solucionable, pero necesita hacer que el uso sea
cat
más complejo (agregando argumentos de línea de comando posicional, por ejemplocat 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.
fuente
cat
de una manera que sea útil y consistente.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.
Referencia: El archivo de correo GCC / GNU .
fuente
wc -l
no contará la última línea de un archivo si no se termina la nueva línea. Además,cat
unirá 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.wc
ha sido ya mencionado ....cat
ywc
)?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:
Fuente: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206
Una línea incompleta como:
Fuente: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195
Un archivo de texto como:
Fuente: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397
Una cadena como:
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
wc
manual de 'leemos:¿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.
Observe que el
cat
tamañ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é
cat
pasa si desea dos archivos cuya salida se convierte en una sola línea en lugar de dos? En otras palabras,cat
hace lo que se supone que debe hacer.El
man
decat
sólo menciona la lectura de entrada hasta EOF, no <nueva línea>. Tenga en cuenta que el-n
cambio decat
tambié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 elman
.)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 filename
uno podría hacerloawk '{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 quecurl
d), 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.
fuente
Puede estar relacionado con la diferencia entre :
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:
fuente
Algunas herramientas esperan esto. Por ejemplo,
wc
espera esto:fuente
wc
no 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.wc -l
imprimir1
en ambos casos, pero algunas personas podrían decir que el segundo caso debería imprimir2
.\n
en 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.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"
fuente
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.
fuente
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
blame
al 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.fuente
\n
). Problema resuelto.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:
wc -l
no contará una "línea" final si no termina con una nueva línea.cat
simplemente funciona y funciona sin complicaciones. Simplemente copia los bytes de cada archivo, sin necesidad de interpretación. No creo que haya un DOS equivalente acat
. El usocopy a+b c
terminará fusionando la última línea de archivoa
con la primera línea de archivob
.fuente
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.
fuente
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 ...
fuente
También hay un problema práctico de programación con archivos que carecen de nuevas líneas al final: el
read
Bash incorporado (no sé sobre otrasread
implementaciones) no funciona como se esperaba:¡Esto solo se
foo
imprime ! La razón es que cuandoread
encuentra la última línea, escribe el contenido$line
pero devuelve el código de salida 1 porque llegó a EOF. Esto rompe elwhile
ciclo, por lo que nunca llegamos a laecho $line
parte. Si desea manejar esta situación, debe hacer lo siguiente:Es decir, haga el
echo
siread
falló 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.fuente
Como bien expresado por muchos, porque:
Muchos programas no se comportan bien o fallan sin él.
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.Los programas rara vez rechazan el final
'\n'
(no sé de ninguno).Sin embargo, esto plantea la siguiente pregunta:
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:
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.Definir claramente, documentar, el manejo del código de un final faltante
'\n'
.No, como sea posible, genere un archivo que carece del final
'\n'
.fuente
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
sed
ysed
omitimos 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.txt
con algúnjson
contenido dentro.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
sed
comandosed 's|value|newValue|g' foo.txt > foo.txt.tmp
El archivo recién generado fue
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.
fuente
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.
fuente
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.
fuente
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.
fuente
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.
fuente