Tengo archivos en subdirectorios del directorio actual que pueden tener o no nuevas líneas al final; ¿Cómo puedo encontrar archivos que no tienen una nueva línea al final?
He intentado esto:
find . -name '*.styl' | while read file; do
awk 'END{print}' $file | grep -E '^$' > /dev/null || echo $file;
done
Pero no funciona. awk 'END{print}' $file
imprime la línea antes de una nueva línea vacía, igual que tail -n 1 $file
.
awk 'END{print}' $file
: esto ignora totalmente el contenido de $ file, y después de terminar de analizar todos los archivos contenidos en "$ file" agrega una nueva línea. Como es lo único que imprime el comando awk, podría reemplazarse por:printf '\n'
(sin ningún mentino de $ file) y hacer lo mismo. Creo que esto NO es lo que buscabas (es decir, ¿imprimir la última línea del archivo?)c
y también FreeBSD, pero no me había dado cuenta de que está documentado como dependiente de la implementación: gnu.org/software/gawk/manual/… . Por lo que no suceda, pero no siempre.Respuestas:
Para aclarar, el carácter LF (también conocido
\n
como nueva línea) es el delimitador de línea , no es el separador de línea. Una línea no está terminada a menos que esté terminada por un carácter de nueva línea. Un archivo que solo contienea\nb
no es un archivo de texto válido porque contiene caracteres después de la última línea. Lo mismo para un archivo que solo contienea
. Un archivo que contienea\n
contiene una línea no vacía.Entonces, un archivo que termina con al menos una línea vacía termina con dos caracteres de nueva línea o contiene un solo carácter de nueva línea.
Si:
Salidas
\n
o\n \n
, entonces el archivo contiene al menos una línea vacía final. Si no genera nada, entonces ese es un archivo vacío, si genera<anything-but-\0> \n
, entonces termina en una línea no vacía. Cualquier otra cosa, no es un archivo de texto.Ahora, para usar eso para encontrar archivos que terminan en una línea vacía, OK, eso es eficiente (especialmente para archivos grandes) ya que solo lee los dos últimos bytes de los archivos, pero primero la salida no es fácilmente analizable programáticamente, especialmente teniendo en cuenta que es no es consistente de una implementación
od
a la siguiente, y tendríamos que ejecutar unotail
y unood
por archivo.(para buscar archivos que terminen en una línea vacía) ejecutaría la menor cantidad de comandos posible, pero significaría leer el contenido completo de todos los archivos.
Idealmente, necesitaría un shell que pueda leer el final de un archivo por sí mismo.
Con
zsh
:fuente
are_textfiles () { nontext=0; rem="return 0 if all args are files with terminating newline, or n [=number of non-textfiles]" ; for f in "$@" ; do [ -f "$f" ] && { tail -c 1 "$f" | od -An -vtc | grep "\\n" ;} >/dev/null 2>&1 || ((nontext++)) ; done ; return $nontext ; }
. Usar como:if ( are_textfiles this that otherthing ) ; then echo all are text files ; else echo "are_textfiles returned : $?" ; fi
Con
gnu sed
y un shell comozsh
(obash
conshopt -s globstar
):esto comprueba si la última línea de cada archivo no está vacía, si es así, imprime el nombre del archivo.
Si desea lo contrario (imprima los nombres de los archivos si la última línea está vacía) simplemente reemplace
/./
con/^$/
fuente
-s
en acción antes. ¡Gracias GNU!Un archivo de texto correctamente terminado con una última línea vacía termina en dos
\n
.Entonces, esperamos que
tail -c2
sea igual a$'\n\n'
.Lamentablemente, las expansiones de comando eliminan las nuevas líneas finales. Necesitaremos un poco de ajustes.
Incluso podríamos expandirnos un poco para verificar qué archivos no tienen una nueva línea final:
Tenga en cuenta que la nueva línea podría cambiarse a algo así como
$'\r\n
si fuera necesario.En ese caso, también cambie
tail -c2
atail -c4
.fuente
fuente
cat $file 2>&1 /dev/null
, o si se trata sólo de Bash,cat $file &> /dev/null
.$file
todos los lugares donde se usa, y por favor, use en$(commands ...)
lugar de`backticks`
...