¿Cómo copio el contenido de cada archivo de una lista en otro archivo?

15

Tengo una lista de nombres de archivo dentro de un archivo llamado list_of_files.txt.

Quiero copiar el contenido de cada archivo en esa lista en otro archivo llamado all_compounds.sdf.

¿Cómo debo hacer esto desde la línea de comando?

Ramita Rajaa
fuente

Respuestas:

20

No use la simple sustitución de comandos para obtener nombres de archivo (que podrían romperse fácilmente con espacios y otros caracteres especiales). Use algo como xargs:

xargs -d '\n' -a list_of_files.txt cat > all_compounds.sdf

O un while readbucle:

while IFS= read -r file; do cat "$file"; done < list_of_files.txt > all_compounds.sdf

Para utilizar la sustitución de comandos de forma segura, al menos establezca IFSsolo la nueva línea y desactive el globbing (expansión de comodines):

(set -f; IFS=$'\n'; cat $(cat list_of_files.txt) > all_compounds.sdf)

Los paréntesis circundantes ()deben ejecutar esto en una subshell, para que su shell actual no se vea afectado por estos cambios.

muru
fuente
14

De manera rápida y sucia ...

cat $(cat list_of_files.txt) >> all_compounds.sdf

Tenga en cuenta: esto solo funciona si los nombres de archivo en su lista se comportan muy bien; las cosas saldrán mal si tienen espacios, líneas nuevas o cualquier carácter que tenga un significado especial para el shell; use esta respuesta para obtener resultados confiables)

Notas

  • catcon cat enates archivos. También imprime sus contenidos.
  • Usando la sustitución de comandos command2 $(command1), puede pasar la salida de command1( cat list...) a command2( cat) que concatena los archivos.
  • Luego use la redirección >>para enviar el resultado a un archivo en lugar de imprimirlo en stdout. Si desea ver la salida, use teeen su lugar:

    cat $(cat list_of_files.txt) | tee -a all_compounds.sdf

(He utilizado en >>lugar de >y teecon el -ainterruptor en caso de que su archivo ya exista; esto se agrega al archivo en lugar de sobrescribirlo, si ya existe)

Zanna
fuente
1
@Zanna cita las sustituciones de comandos para evitar la división de palabras, como"$(cat list_of_files.txt)"
Sergiy Kolodyazhnyy
44
@Serg si no se realiza la división de palabras, catobtiene la lista completa como un argumento.
Muru
@muru OK, ¿cómo lidiamos con los nombres de archivo que contienen espacios, entonces?
Sergiy Kolodyazhnyy
1
@Serg estableció IFS en consecuencia - vea el último párrafo de mi respuesta
muru
4

Si bien GNU awkes una utilidad de procesamiento de texto, permite ejecutar comandos de shell externos a través de una system()llamada. Podemos utilizar eso para nuestra ventaja así:

$ awk '{cmd=sprintf("cat \"%s\"",$0); system(cmd)}' file_list.txt                                                        

La idea aquí es simple: leemos el archivo línea por línea, y de cada línea creamos una cadena formateada cat "File name.txt", que luego se pasa asystem() .

Y aquí está en acción:

$ ls
file1.txt  file2.txt  file3 with space.txt  file_list.txt


$ awk '{cmd=sprintf("cat \"%s\"",$0); system(cmd)}' file_list.txt                                                        
Hi, I'm file2
Hi, I'm file1
Hi, I'm file3

Ya hemos hecho la mayor parte de la tarea allí: imprimimos todos los archivos de la lista. El resto es simple: redirija la salida final al archivo con el >operador en el archivo de resumen.

awk '{cmd=sprintf("cat \"%s\"",$0); system(cmd)}' file_list.txt > output.txt
Sergiy Kolodyazhnyy
fuente