2011-01-07 9 views
17

¿Cómo puedo listar los nombres de archivo de texto normal (.txt), que no terminan con una nueva línea?¿Cómo puedo listar los archivos que no terminan con una nueva línea?

lista

ej .: (salida) este nombre de archivo:

$ cat a.txt 
asdfasdlsad4randomcharsf 
asdfasdfaasdf43randomcharssdf 
$ 

y no lista (salida) este nombre de archivo:

$ cat b.txt 
asdfasdlsad4randomcharsf 
asdfasdfaasdf43randomcharssdf 

$ 
+0

¿Está buscando simplemente una amplia pantalla de archivos desde una carpeta hacia abajo? Su pregunta no está muy clara en el ejemplo anterior. – James

+2

¿Qué significa "txt normal"? ¿Estás hablando de archivos que terminan con una línea * en blanco * (\ n \ n) o solo archivos que finalizan con una nueva línea? Puede usar 'od -c filename' para imprimir una representación inequívoca del archivo. – jfs

+1

Solo para enfatizar: newline es * no * lo mismo que * línea * en blanco. Una nueva línea es un carácter único: delimita lo que vemos como "líneas". Una línea en blanco es simplemente una "línea" sin caracteres, generalmente 2 caracteres consecutivos de línea nueva sin nada intermedio, o la primera línea de un archivo que comienza con una nueva línea. Algunas personas llaman a líneas que consisten solo en líneas en blanco del espacio en blanco, y reservan el término "línea vacía" para 2 caracteres consecutivos de línea nueva. Debe tener claro lo que quiere. – jw013

Respuesta

2

Esto es kludgy; alguien seguramente puede hacerlo mejor:

for f in `find . -name '*.txt' -type f`; do 
    if test `tail -c 1 "$f" | od -c | head -n 1 | tail -c 3` != \\n; then 
     echo $f; 
    fi 
done 

N.B. esto responde a la pregunta en el título, que es diferente de la pregunta en el cuerpo (que está buscando archivos que terminan con \ n \ n, creo).

2

Esto debería hacer el truco:

#!/bin/bash 

for file in `find $1 -type f -name "*.txt"`; 
do 
     nlines=`tail -n 1 $file | grep '^$' | wc -l` 
     if [ $nlines -eq 1 ] 
       then echo $file 
     fi 
done; 

ha decirlo así: ./script dir

P. ej ./script /home/user/Documents/ -> enumera todos los archivos de texto en /home/user/Documents terminando con \n.

+0

La primera mejora es poner 'IFS = $ '\ n'' antes para. Permite manejar archivos con espacios. La segunda mejora es reemplazar '$ nlines -eq 1' con' $ nlines -eq 0' porque el autor necesita "nombres de archivo, eso ** no termina ** con una nueva línea". –

7

seguirlo:

find -type f -exec sh -c '[ -z "$(sed -n "\$p" "$1")" ]' _ {} \; -print 

Se imprimirá nombres de archivo de los archivos que terminan con una línea en blanco. Para imprimir archivos que no terminan en una línea en blanco, cambie -z a -n.

+1

Las respuestas que usan 'for ... find ... do' fallarán si hay nombres de archivo que contienen espacios. –

+1

tiene razón acerca de 'para ... encontrar ...' http://mywiki.wooledge.org/BashPitfalls#for_i_in_.24.28ls_.2A.mp3.29 – jfs

+1

Excelente solución. Recomiende que no haga eco como parte del script 'sh' y agregue' -print' al final del comando find. Entonces la '-print' se puede modificar a lo que sea necesario (por ejemplo,' -print0'). – squid314

1

Otra opción:

$ find . -name "*.txt" -print0 | xargs -0I {} bash -c '[ -z "$(tail -n 1 {})" ] && echo {}' 
+0

Muchas gracias, este es el único ejemplo en este hilo que realmente funciona (en OSX) –

+0

... en realidad, esto no parece encontrar los archivos correctos –

0

Debido a que su pregunta tiene la etiqueta Perl, voy a publicar una respuesta que lo utiliza:

find . -type f -name '*.txt' -exec perl check.pl {} + 

donde check.pl es la siguiente:

#!/bin/perl 

use strict; 
use warnings; 

foreach (@ARGV) { 
    open(FILE, $_); 

    seek(FILE, -2, 2); 

    my $c; 

    read(FILE,$c,1); 
    if ($c ne "\n") { 
     print "$_\n"; 
    } 
    close(FILE); 
} 

Este script perl acaba de abrir, uno por vez, los archivos pasan como parámetros y solo leen el penúltimo; si no es un carácter de nueva línea, solo imprime el nombre del archivo, de lo contrario no hace nada.

+0

¿Qué pasa si el último carácter no es una nueva línea (por supuesto no es un archivo de texto válido)? –

17

Uso pcregrep, una versión compatible expresiones regulares de Perl de grep que soporta un modo multi-uso de la bandera -M que puede ser utilizado para coincidir (o no coincidir) si la última línea tenía una nueva línea:

pcregrep -LMr '\n$' . 

en el ejemplo anterior estamos diciendo a buscar de forma recursiva (-r) en el directorio actual (.) el listado de archivos que no coinciden (-L) nuestra línea múltiple (-M) de expresiones regulares que busca una nueva línea al final de un archivo ('\n$')

Cambiando -L a -l enumeraría los archivos que hacen tienen nuevas líneas en ellos.

+0

Debo señalar que la respuesta dada por @ dennis-williamson también falla para los archivos que tienen espacios en ellos. Al menos lo hizo por mí. –

+0

Agregué un conjunto de citas faltantes en mi respuesta que deberían resolver ese problema. –

+1

Solo una nota para lectores futuros: este comando pcregrep es correcto para archivos que * no * contienen líneas vacías. Contraejemplo: 'printf" a \ n \ nb "| pcregrep -M '\ n $' -' imprimirá 'a' (y por lo tanto, al ejecutar con' -L' no se imprimirá nada). – maverickwoo

14

Ok es mi turno, me daría una oportunidad:

find -type f -print0 | xargs -0 -L1 bash -c 'test "$(tail -c 1 "$0")" && echo "No new line at end of $0"' 
1

Este ejemplo funciona para mí en OSX (muchas de las soluciones anteriores no lo hicieron)

for file in `find . -name "*.java"` 
do 
    result=`od -An -tc -j $(($(ls -l $file | awk '{print $5}') - 1)) $file` 
    last_char=`echo $result | sed 's/ *//'` 
    if [ "$last_char" != "\n" ] 
    then 
    #echo "Last char is .$last_char." 
    echo $file 
    fi 
done 
3

Si está utilizando ' ACK'(http://beyondgrep.com) como una alternativa a grep, que acaba de ejecutar esta:

ack -v '\n$' 

en realidad, busca en todas las líneas que no coinciden (-v) con una nueva línea al final de la línea.

+1

Solución fácil y simple. Agregue '-l' para obtener solo los archivos coincidentes y no la línea. – stu42j

1

La mayoría de las soluciones en esta página no funcionan para mí (FreeBSD 10.3 amd64). solución OSX de Ian Will hace el trabajo casi siempre, pero es bastante difícil de seguir: - (

Hay una solución fácil que casi siempre funciona demasiado: (si $ f es el archivo):

sed -i '' -e '$ a \' "$ f"

Hay un gran problema con la solución sed:. nunca le da la oportunidad a sólo comprobar (y no añadir una nueva línea)

Ambas soluciones anteriores fallan para los archivos DOS. Creo que la solución portátil/de secuencias de comandos más es problemática. hábilmente el más fácil, que desarrollé yo mismo: -)

Aquí está el script sh elemental que combina file/unix2dos/tail. En producción, es probable que necesite usar "$ f" entre comillas a buscar a la salida de la cola (incrustado en la variable de shell llamado pasado) como \ "$ f \"

if file $f | grep 'ASCII text' > /dev/null; then 
    if file $f | grep 'CRLF' > /dev/null; then 
     type unix2dos > /dev/null || exit 1 
     dos2unix $f 
     last="`tail -c1 $f`" 
     [ -n "$last" ] && echo >> $f 
     unix2dos $f 
    else 
     last="`tail -c1 $f`" 
     [ -n "$last" ] && echo >> $f 
    fi 
fi 

Espero que esto ayude a alguien.

Cuestiones relacionadas