Al usar los sistemas de control de versiones, me molesta el ruido cuando dice el diff No newline at end of file
.
Entonces me preguntaba: ¿Cómo agregar una nueva línea al final de un archivo para deshacerme de esos mensajes?
bash
shell
text-processing
newlines
k0pernikus
fuente
fuente
Respuestas:
Para desinfectar recursivamente un proyecto, uso este oneliner:
Explicación:
git ls-files -z
enumera los archivos en el repositorio. Toma un patrón opcional como parámetro adicional que puede ser útil en algunos casos si desea restringir la operación a ciertos archivos / directorios. Como alternativa, puede usarfind -print0 ...
programas similares para enumerar los archivos afectados, solo asegúrese de que emitaNUL
entradas delimitadas.while IFS= read -rd '' f; do ... done
itera a través de las entradas, manejando de manera segura los nombres de archivo que incluyen espacios en blanco y / o nuevas líneas.tail -c1 < "$f"
lee el último carácter de un archivo.read -r _
sale con un estado de salida distinto de cero si falta una nueva línea final.|| echo >> "$f"
agrega una nueva línea al archivo si el estado de salida del comando anterior era distinto de cero.fuente
find -name \*.java | while read f; do tail -n1 $f | read -r _ || echo >> $f; done
git ls-files
que aún le ahorrará editar archivos que no se rastrean en el control de versiones.IFS=
para desarmar el separador es bueno para preservar el espacio en blanco circundante. Las entradas terminadas en nulo solo son relevantes si tiene archivos o directorios con una nueva línea en su nombre, lo que parece un poco descabellado, pero es la forma más correcta de manejar el caso genérico, estoy de acuerdo. Como una pequeña advertencia: la-d
opciónread
no está disponible en POSIX sh.tail -n1 < "$f"
para evitar problemas con los nombres de archivo que comienzan con-
(tail -n1 -- "$f"
no funciona para el archivo llamado-
). Es posible que desee aclarar que la respuesta ahora es específica de zsh / bash.Aquí tiene :
Y alternativamente para OS X
sed
:Esto se agrega
\n
al final del archivo solo si aún no termina con una nueva línea. Entonces, si lo ejecuta dos veces, no agregará otra nueva línea:fuente
man sed
:$ Match the last line.
Pero tal vez solo funciona por accidente. Tu solución también funciona.$
coincide con la última línea, ¿por qué no agrega otra nueva línea a una cadena que ya contiene una nueva línea?$
. Dentro de una expresión regular, como con el formulario/<regex>/
, tiene el significado habitual de "final de línea de coincidencia". De lo contrario, se usa como dirección, sed le da el significado especial de "última línea en el archivo". El código funciona porque sed por defecto agrega una nueva línea a su salida si aún no está allí. El código "$ a \" solo dice "coincide con la última línea del archivo y no le agrega nada". Pero implícitamente, sed agrega la nueva línea a cada línea que procesa (como esta$
línea) si aún no está allí./regex/
le da un significado diferente. Las páginas de manual de FreeBSD son un poco más informativo, pienso: freebsd.org/cgi/man.cgi?query=sedEchar un vistazo:
entonces
echo "" >> noeol-file
debería hacer el truco. (¿O quiso pedir identificar estos archivos y corregirlos?)editar retira el
""
deecho "" >> foo
(ver el comentario de @ yuyichao) Edit2 añadió el""
nuevo ( pero ver el comentario de @Keith Thompson)fuente
""
no es necesario (al menos para bash) ytail -1 | wc -l
puede usarse para encontrar el archivo sin una nueva línea al final""
es necesario para bash, pero he vistoecho
implementaciones que no imprimen nada cuando se invoca sin argumentos (aunque ninguno de los que puedo encontrar ahora hace esto).echo "" >> noeol-file
Es probablemente un poco más robusto.printf "\n" >> noeol-file
es aún más.csh
'secho
es la que se conoce a la salida de nada cuando no se pasa ningún argumento. Pero entonces, si vamos a apoyar conchas no Bourne-como, debemos hacer queecho ''
en lugar deecho ""
comoecho ""
sería ouput""<newline>
conrc
oes
por ejemplo.tcsh
, a diferenciacsh
, imprime una nueva línea cuando se invoca sin argumentos, independientemente de la configuración de$echo_style
.Otra solución usando
ed
. Esta solución solo afecta a la última línea y solo si\n
falta:Básicamente funciona abriendo el archivo para editarlo a través de un script, el script es el
w
comando único que escribe el archivo nuevamente en el disco. Se basa en esta oración que se encuentra en laed(1)
página del manual:fuente
Una manera simple, portátil y compatible con POSIX de agregar una nueva línea final ausente a un archivo de texto sería:
Este enfoque no necesita leer el archivo completo; simplemente puede buscar EOF y trabajar desde allí.
Este enfoque tampoco necesita crear archivos temporales a sus espaldas (por ejemplo, sed -i), por lo que los enlaces duros no se ven afectados.
echo agrega una nueva línea al archivo solo cuando el resultado de la sustitución del comando es una cadena no vacía. Tenga en cuenta que esto solo puede suceder si el archivo no está vacío y el último byte no es una nueva línea.
Si el último byte del archivo es una nueva línea, tail lo devuelve, luego la sustitución del comando lo elimina; El resultado es una cadena vacía. La prueba -n falla y echo no se ejecuta.
Si el archivo está vacío, el resultado de la sustitución del comando también es una cadena vacía, y nuevamente echo no se ejecuta. Esto es deseable, porque un archivo vacío no es un archivo de texto no válido, ni es equivalente a un archivo de texto no vacío con una línea vacía.
fuente
yash
si el último carácter del archivo es un carácter de varios bytes (en las configuraciones regionales UTF-8, por ejemplo), o si la configuración regional es C y el último byte del archivo tiene el octavo bit establecido. Con otros shells (excepto zsh), no agregaría una nueva línea si el archivo terminara en un byte NUL (pero nuevamente, eso significaría que la entrada no será de texto incluso después de agregar una nueva línea).Agregar nueva línea independientemente:
Aquí hay una manera de verificar si existe una nueva línea al final antes de agregar una, utilizando Python:
fuente
echo ""
Parece más robusto queecho -n '\n'
. O podría usarprintf '\n'
La solución más rápida es:
Es realmente rapido.
En un archivo de tamaño mediano,
seq 99999999 >file
esto lleva milisegundos.Otras soluciones llevan mucho tiempo:
Funciona en ash, bash, lksh, mksh, ksh93, attsh y zsh pero no en yash.
Todas las demás soluciones presentadas aquí cambian la marca de tiempo del archivo.
Si necesita una solución portátil para cortar (y todos los demás shells enumerados anteriormente), puede ser un poco más complejo:
fuente
La forma más rápida de probar si el último byte de un archivo es una nueva línea es leer solo ese último byte. Eso podría hacerse con
tail -c1 file
. Sin embargo, la forma simplista de probar si el valor de byte es una nueva línea, dependiendo de la eliminación habitual de una nueva línea final dentro de una expansión de comando falla (por ejemplo) en yash, cuando el último carácter del archivo es un UTF- 8 valor.La forma correcta, compatible con POSIX, de todos los shells (razonables) para encontrar si el último byte de un archivo es una nueva línea es usar xxd o hexdump:
Luego, comparar la salida de arriba
0A
proporcionará una prueba robusta.Es útil para evitar agregar una nueva línea a un archivo vacío.
Archivo que no proporcionará un último carácter de
0A
, por supuesto:Corto y dulce. Esto lleva muy poco tiempo, ya que solo lee el último byte (buscar EOF). No importa si el archivo es grande. Luego solo agregue un byte si es necesario.
No se necesitan ni se usan archivos temporales. No hay enlaces duros afectados.
Si esta prueba se ejecuta dos veces, no agregará otra nueva línea.
fuente
xxd
nihexdump
las utilidades POSIX tampoco . En el cofre de herramientas POSIX, hayod -An -tx1
que obtener el valor hexadecimal de un byte.Es mejor corregir el editor del usuario que editó el archivo por última vez. Si usted es la última persona que ha editado el archivo, ¿qué editor está utilizando, supongo que textmate ...?
fuente
emacs
no añada una nueva línea al final del archivo.(setq require-final-newline 'ask)
en mi.emacs
Si solo desea agregar rápidamente una nueva línea al procesar alguna tubería, use esto:
También es compatible con POSIX.
Luego, por supuesto, puede redirigirlo a un archivo.
fuente
cat file.csv | tr "\r" "\n" | { cat; echo; } | sed "/^[[:space:]]*$/d" | tail -n +2 | wc -l
Siempre que no haya valores nulos en la entrada:
... bastaría con añadir siempre una nueva línea al final de un archivo si aún no tenía una. Y solo necesita leer el archivo de entrada una vez para hacerlo bien.
fuente
paste infile 1<> infile
lugar.Aunque no responde directamente a la pregunta, aquí hay un script relacionado que escribí para detectar archivos que no terminan en nueva línea. Es muy rápido.
El script perl lee una lista de nombres de archivos (opcionalmente ordenados) desde stdin y para cada archivo lee el último byte para determinar si el archivo termina en una nueva línea o no. Es muy rápido porque evita leer todo el contenido de cada archivo. Produce una línea para cada archivo que lee, con el prefijo "error:" si se produce algún tipo de error, "vacío:" si el archivo está vacío (¡no termina con nueva línea!), "EOL:" ("fin de línea ") si el archivo termina con nueva línea y" sin EOL: "si el archivo no termina con nueva línea.
Nota: el script no maneja los nombres de archivo que contienen nuevas líneas. Si está en un sistema GNU o BSD, puede manejar todos los nombres de archivo posibles agregando -print0 para buscar, -z para ordenar y -0 para perl, de esta manera:
Por supuesto, aún tendría que encontrar una forma de codificar los nombres de archivo con nuevas líneas en la salida (dejada como ejercicio para el lector).
La salida podría filtrarse, si se desea, para agregar una nueva línea a aquellos archivos que no tienen uno, más simplemente con
La falta de una nueva línea final puede causar errores en las secuencias de comandos, ya que algunas versiones de shell y otras utilidades no manejarán correctamente una nueva línea final faltante al leer dicho archivo.
En mi experiencia, la falta de una nueva línea final se debe al uso de varias utilidades de Windows para editar archivos. Nunca he visto que vim cause una nueva línea final faltante al editar un archivo, aunque informará sobre dichos archivos.
Finalmente, hay secuencias de comandos mucho más cortas (pero más lentas) que pueden recorrer sus entradas de nombre de archivo para imprimir aquellos archivos que no terminan en nueva línea, como:
fuente
Los
vi
/vim
/ex
editores agregan automáticamente<EOL>
en EOF a menos que el archivo ya lo tenga.Así que prueba cualquiera de los dos:
que es equivalente a:
Pruebas:
Para corregir varios archivos, verifique: ¿Cómo reparar 'No hay nueva línea al final del archivo' para muchos archivos? en SO
¿Por qué esto es tan importante? Para mantener nuestros archivos POSIX compatibles .
fuente
Para aplicar la respuesta aceptada a todos los archivos en el directorio actual (más subdirectorios):
Esto funciona en Linux (Ubuntu). En OS X, probablemente tenga que usar
-i ''
(no probado).fuente
find .
enumera todos los archivos, incluidos los archivos en.git
. Para excluir:find . -type f -not -path './.git/*' -exec sed -i -e '$a\' {} \;
Al menos en las versiones de GNU, simplemente
grep ''
oawk 1
canoniza su entrada, agregando una nueva línea final si aún no está presente. Copian el archivo en el proceso, lo que lleva tiempo si es grande (¿pero la fuente no debería ser demasiado grande para leer de todos modos?) Y actualiza el modtime a menos que haga algo como(aunque puede estar bien en un archivo que está registrando porque lo modificó) y pierde enlaces duros, permisos no predeterminados y ACL, etc. a menos que sea aún más cuidadoso.
fuente
grep '' file 1<> file
, aunque todavía leería y escribiría el archivo por completo.Esto funciona en AIX ksh:
En mi caso, si al archivo le falta la nueva línea, el
wc
comando devuelve un valor de2
y escribimos una nueva línea.fuente
Agregando a la respuesta de Patrick Oscity , si solo desea aplicarlo a un directorio específico, también puede usar:
find -type f | while read f; do tail -n1 $f | read -r _ || echo >> $f; done
Ejecute esto dentro del directorio al que desea agregar nuevas líneas.
fuente
echo $'' >> <FILE_NAME>
agregará una línea en blanco al final del archivo.echo $'\n\n' >> <FILE_NAME>
agregará 3 líneas en blanco al final del archivo.fuente
Si su archivo finaliza con terminaciones de línea de Windows
\r\n
y está en Linux, puede usar estesed
comando. Solo se agrega\r\n
a la última línea si aún no está allí:Explicación:
Si la última línea ya contiene un,
\r\n
entonces la expresión regular de búsqueda no coincidirá, por lo tanto, no sucederá nada.fuente
Podrías escribir un
fix-non-delimited-line
guión como:Contrariamente a algunas de las soluciones dadas aquí,
Puedes usarlo por ejemplo como:
o:
POSIXY, podría hacer algo funcionalmente equivalente con
fuente