2010-07-16 9 views
9

Tengo una gran cantidad de archivos fuente que carecen de una nueva línea al final.Cómo reparar la advertencia "No hay nueva línea al final del archivo" para muchos archivos?

¿Cómo agrego automáticamente una nueva línea al final de cada uno de ellos?

Es posible que algunos ya tengan una nueva línea, por lo que solo se debe agregar si es necesario.

Probablemente no estoy buscando el código, per se, sino algo que puedo ejecutar en Terminal para agregar las nuevas líneas necesarias (o algún tipo de herramienta de programación o desarrollo).

Respuesta

3

Respuesta de Norman convertida a un liner dividido por conveniencia.

for i in * ; do echo $i; \ 
if diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo >> "$i"; \ 
fi; done 

reemplazar * con cualquier patrón de archivo que desea, por ejemplo *.c

Y otro que usted acaba de decir qué archivos están rotos:

for i in * ; do \ 
if diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo $i; \ 
fi; done 
+0

Ninguna de las soluciones funciona para mí –

+1

Si quieres que funcione recursivamente, puedes cambiar '*' con '$ (find. -type f)' o '$ (find -type f -name )' – durron597

7

Si usted tiene acceso a las herramientas de Unix, puede ejecutar diff para averiguar qué archivos carecen de un salto de línea y luego añadirlo:

#!/bin/sh 
for i 
do 
    if diff /dev/null "$i" | tail -1 | grep '^\\ No newline' > /dev/null 
    then 
    echo >> "$i" 
    fi 
done 

estoy confiando en diff para producir el mensaje con un \ en la primera columna, tail para darme la última línea de salida de diff, y grep para decirme si la última línea es el mensaje que estoy buscando. Si todo funciona, entonces el echo produce una nueva línea y el >> lo agrega al archivo "$i". Las comillas alrededor de "$i" aseguran que las cosas sigan funcionando si el nombre de archivo tiene espacios.

+2

No está mal, pero grep devuelve un mensaje localizado, como "\ Brak znaku nowej linii (etc.)". Además, el diff genera todo el archivo. Yo usaría 'tail -1 $ f | grep '\ n'' para la condición (funciona en mi caja). –

+0

@TomaszGandor: 'cola -1 nombre de archivo | grep '\ n' parece siempre devolver un resultado falso en mi mac, independientemente de si hay una nueva línea rastreada o no ... – Gino

2

bien, después de quejarse en los comentarios, hay mi mejor solución primer lugar, usted quiere saber, qué archivos son los saltos de línea faltaba:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -print 

No es super rápido (llamar a un par de procesos para cada archivo), pero está bien para un uso práctico.

Ahora, cuando lo tienes, es posible que así agregar la nueva línea, con otro -exec:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -exec sh -c "echo >> {}" ';' 

posibles trampas:

  • si los nombres de archivo son malas, por ejemplo, tienen espacios, puede necesitar tail -1 \"{}\". ¿O lo hace hacerlo bien?

  • es posible que desee agregar más filtros para buscar, como -name \*py, o similares.

  • pensar en posibles DOS/Unix nuevas líneas lío antes de su uso (corregir eso primero).

EDIT:

Si no te gusta el resultado de estos comandos (haciéndose eco de algunos hex), añadir -q a grep:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -q -v 0a$" ';' -print 
find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -q -v 0a$" ';' -exec sh -c "echo >> {}" ';' 
+1

Esto es * enorme * exagerado. – tripleee

0

Debido a comandar la localización Tim y Norman respuesta Se mejorará con el prefijo 'LANG = C' para tener la posibilidad de coincidir con el patrón 'Sin línea nueva' con cada sistema que tenga parámetros regionales

Esto asegura una línea vacía final a cada archivo puesto en la línea de comandos de este script:

#!/bin/sh -f 
for i in $* ; do echo $i; \ 
if LANG=C diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo >> "$i"; \ 
fi; done 

Y este script detecta archivos que carecen de ella:

#!/bin/sh -f 
for i in $* ; do \ 
if LANG=C diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo $i; \ 
fi; done 
1

Try ex manera:

ex -s +"bufdo wq" *.c 

Y de forma recursiva (con a new globbing option activado):

ex -s +"bufdo wq" **/*.c 

Esto es equivalente a vi -es. Cambie *.c a la extensión de su interés.

El ex/vi agregará automáticamente nueva línea al guardar si no está presente.

0

Después de encontrar la herramienta haga este trabajo sin suerte. Me decido a escribir mi propia

Ésta es mi script en Python para hacer ese trabajo

Sólo anexar (\ r n \) para presentar no contiene (\ n) al final del archivo

https://github.com/tranhuanltv/append_newline

Uso: ./projects .c append_newline.py ./result_dir

solicitudes poner cara de desagrado si quieres

+0

Esto es muy cuestionable: la búsqueda de -1 desde END está bien, pero podría mezclar líneas nuevas de Unix y DOS de esta manera ... –

0

me sorprende que nadie ha mencionado que muchas herramientas simples de procesamiento de texto como Awk agregarán una línea nueva como efecto secundario. Aquí hay un bucle simple que sobrescribirá un archivo solo si se agregó una nueva línea.

for f in *; do 
    awk 1 "$f" >tmp 
    cmp -s tmp "$f" || mv tmp "$f" 
done 
rm -f tmp 

(El archivo temporal es, obviamente, un poco una verruga.)

demostración Ideone: http://ideone.com/HpRHcx

0
pcregrep --recursive --exclude-dir=.git \ 
    --files-without-match --multiline '\n\z' . | 
    while read k ; do echo >> "$k"; done 

Hay varios pasos involucrados aquí:

  1. encuentran de forma recursiva archivos
  2. detectar qué archivos carecen de una nueva línea de fuga
  3. bucle sobre cada una de esos archivos
  4. Añadir la nueva línea

Paso 1 se hace tradicionalmente con find (siguiendo la tradición Unix de "cada herramienta haciendo una cosa y hacerlo bien"), pero desde pcregrep tiene soporte incorporado, me siento cómodo usarlo. Tengo cuidado de evitar meterme con la carpeta .git.

Paso 2 se realiza con una expresión regular de líneas múltiples archivos coincidentes que hacer tienen un salto de línea final, y la impresión de los nombres de los archivos que no lo hacen partido.

El paso 3 se realiza con un ciclo while/read en lugar de un for/in, ya que este último falla para nombres de archivos con espacios y para listas extremadamente largas de archivos.

El paso 4 es un eco simple, siguiendo el enfoque de @norman-ramsey.

h/t @ anthony-bush https://stackoverflow.com/a/20687956/577438 para la sugerencia de pcregrep.

1

estoy usando find en lugar de for f in * ya que es recursiva y la pregunta era acerca de "gran número de archivos de origen".

Estoy usando while read en lugar de find -exec o xargs por razones de rendimiento, se ahorra el proceso de shell de desove siempre.

Estoy aprovechando el hecho de que el operador de backtick está devolviendo la salida del comando "con cualquier línea de nueva final borrada" man bash, por lo que para los archivos terminados apropiadamente, el backtick estará vacío y el eco se saltará.

La pareja find | read fallará en nombres de archivo que contienen nuevas líneas, pero es fácil de solucionar si se requiere:

find -type f -print0 | while read -d $'\0' f; do [[ `tail -c1 "$f"` ]] && echo >> "$f"; done

0

A continuación es mi solución escritura del golpe. Primero verifica que el archivo sea un archivo de texto. Luego, si se trata de un archivo de texto, usa tail y od (octal dump) para ver si el último carácter es el carácter de nueva línea.Si no es así, entonces se añade una nueva línea utilizando eco:

item="$1" 

if file "$item" | egrep '\btext\b' > /dev/null 
then 
    if ! tail -c 1 "$item" | od -b -A n | egrep '\b012\b' > /dev/null 
    then 
     echo "(appending final newline to ${item})" 
     echo >> "$item" 
    fi 
fi 
1

Una solución simple para los archivos que están "ausentes" salto de línea al final del archivo es simplemente sed; las siguientes correcciones en el archivo "in situ" (usando la opción "-i"):

find . -type f -exec sed -i -e '$a\' {} \; -print 

Explicación: encontrar todos los archivos (-type f), a cargo sed, cambiar los archivos en el lugar (-i), teniendo en cuenta el siguiente (-e) secuencia de comandos/expresión, que coincide con el final del archivo ($) y realiza la acción "agregar" (a\), pero en realidad no especifica ningún texto para agregar (nada después del \) que va para agregar una nueva línea al final del archivo, pero solo si falta. Imprime todos los archivos encontrados (fijos o no), lo que probablemente sea innecesario.

La advertencia principal es que las características sed varían según las plataformas, por lo que -i y -e pueden ser compatibles o no; p.ej. las antiguas rarezas de Unix o MacOS pueden requerir una sintaxis ligeramente diferente.

Cuestiones relacionadas