Forzar nuevas líneas con impresión de comodines de gato

9

Quiero usar cat con comodines en bash para imprimir varios archivos pequeños (cada archivo es una oración) a la salida estándar. Sin embargo, el contenido del archivo separado no está separado por una nueva línea, lo que me gustaría para facilitar la lectura.

¿Cómo puedo agregar un delimitador de archivo de algún tipo a este comando?

lennyklb
fuente

Respuestas:

12

Defina una función de shell que genere un final de línea después de cada archivo y úselo en lugar de cat:

endlcat() {
  for file in "$@"; do
    cat -- "$file"
    echo
  done
}

entonces puedes usar endlcat *.

El forbucle recorre todos los argumentos proporcionados ( $@) que el shell ya escapa cuando usa comodines como *. Se --requiere que no se ahogue con los nombres de archivo que comienzan con un guión. Finalmente las echosalidas de una nueva línea.

Marco
fuente
¡Parece bastante obvio usar la iteración en retrospectiva! Pensé que podría haber una bandera en el gato, ¡pero esto también funciona! Gracias.
lennyklb
No necesita el in "$@"- es implícito.
l0b0
44
ser explícito es bueno para la legibilidad.
cas
5

Simplemente use un bucle en lugar de simple cat:

for file in /path/to/targetdir/*; do
    echo "-------- $file -------"
    cat "$file" 
done
terdon
fuente
Funciona como la respuesta aceptada, pero esa también tenía el siguiente paso hacia la línea de comandos, así que acepté la otra.
lennyklb
3

Si desea un nombre de archivo entre archivos, use tail:

tail -n +1 ./*

(En caso de que desee en taclugar de cat, alguna tailimplementación tiene la -ropción de tacfuncional equivalente )

Cuonglm
fuente
3

Esto funcionará:

sed '' -- *

No necesita ningún bucle de shell o de otro modo, y esto siempre seguirá el resultado de un archivo con una línea de \nconexión, excepto quizás el último.

De lo contrario, si desea que se genere una línea en blanco entre la salida de cada archivo, esto podría funcionar:

bpaste(){
    eval "paste -'sd\n' -- $(x=0;for f do printf "\"\${$((x+=1))}\" - ";done)"
}   </dev/null

Eso siempre seguirá la salida de un archivo con una línea \nelectrónica y una línea en blanco adicional .

Puedes llamarlo así:

bpaste *
mikeserv
fuente
@cuonglm: la operación quiere una nueva línea entre archivos. Esto asegura una nueva línea entre los archivos.
mikeserv
@cuonglm: deberías intentarlo de nuevo. for n in 1 2 3; do printf "$n" >"$n"; done; sed '' -- [123]
mikeserv
@cuonglm: cualquiera seddebe imprimir siempre una línea \nelectrónica antes de imprimir cualquier otra cosa, aunque la última línea del último archivo podría no tener una línea \nelectrónica adjunta. Podría jurar que he respondido esta pregunta antes.
mikeserv
@cuonglm: no entiendo lo que quieres decir. ese pequeño cascarón que acabo de darte huellas 1\n2\n3. funciona. siempre lo hace ¿Qué imprime para ti?
mikeserv
1
@DennisWilliamson: Usar \nen RHS no es estándar. Puedes usar sed -e '$G'.
Cuonglm
2

Similar a la respuesta de @terdon , si prefieres ver el nombre de archivo también en el futuro, puedes usar el headcomando:

$ head *file*
==> file_1 <==
file 1 content

==> file_2 <==
file 2 content

==> file_3 <==
file 3 content

headel valor predeterminado es las primeras 10 líneas, por lo que usarlo sin opciones de comando para su caso (una oración por archivo) está perfectamente bien. De lo contrario, necesita la -n Xopción.

hjk
fuente
2

Otra forma: use grep -hpara buscar simplemente la cadena vacía en cada archivo. Esto coincidirá con todas las líneas, independientemente de cuántas o si la nueva línea haya terminado o no. Los resultados de grep son siempre terminados en nueva línea. La -hopción suprime el prefijo de cada línea de salida con el nombre de archivo del que proviene:

$ printf 'a' > a
$ printf 'b\nB' > b
$ printf 'c\n' > c
$ ls
a  b  c
$ cat -- *
ab
Bc
$ grep -h '' *
a
b
B
c
$ 

O podría usar GNU pasteen -smodo erial con nueva línea como delimitador:

$ paste -s -d '\n' -- *
a
b
B
c
$ 
Trauma digital
fuente