Comment copier le contenu de chaque fichier d'une liste dans un autre fichier?

15

J'ai une liste de noms de fichiers dans un fichier appelé list_of_files.txt.

Je veux copier le contenu de chaque fichier de cette liste dans un autre fichier appelé all_compounds.sdf.

Comment dois-je procéder à partir de la ligne de commande?

Ramita Rajaa
la source

Réponses:

20

N'utilisez pas de substitution de commande simple pour obtenir les noms de fichiers (qui pourraient facilement rompre avec les espaces et autres caractères spéciaux). Utilisez quelque chose comme xargs:

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

Ou une while readboucle:

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

Pour utiliser la substitution de commandes en toute sécurité, définissez au moins IFSuniquement la nouvelle ligne et désactivez la globalisation (expansion avec caractères génériques):

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

Les parenthèses environnantes ()doivent exécuter ceci dans un sous-shell, afin que votre shell actuel ne soit pas affecté par ces changements.

muru
la source
14

Façon rapide et sale ...

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

Veuillez noter: cela ne fonctionne que si les noms de fichiers dans votre liste se comportent très bien - les choses iront mal s'ils ont des espaces, des nouvelles lignes ou des caractères qui ont une signification particulière pour le shell - utilisez plutôt cette réponse pour des résultats fiables)

Remarques

  • catcon cat enate les fichiers. Il imprime également leur contenu.
  • En utilisant la substitution de commandes, command2 $(command1)vous pouvez passer la sortie de command1( cat list...) à command2( cat) qui concatène les fichiers.
  • Utilisez ensuite la redirection >>pour envoyer la sortie vers un fichier au lieu d'imprimer vers stdout. Si vous voulez voir la sortie, utilisez teeplutôt:

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

(J'ai utilisé à la >>place de >et teeavec le -acommutateur au cas où votre fichier existe déjà - cela s'ajoute au fichier au lieu de le remplacer, s'il existe déjà)

Zanna
la source
1
@Zanna cite les substitutions de commandes pour éviter le fractionnement de mots, comme"$(cat list_of_files.txt)"
Sergiy Kolodyazhnyy
4
@Serg si le fractionnement de mots n'est pas effectué, catobtient alors la liste entière en un seul argument.
muru
@muru OK, comment gérer les noms de fichiers contenant des espaces, alors?
Sergiy Kolodyazhnyy
1
@Serg a défini IFS en conséquence - voir le dernier paragraphe de ma réponse
muru
4

Bien que GNU awksoit un utilitaire de traitement de texte, il permet d'exécuter des commandes shell externes via system()appel. Nous pouvons utiliser cela à notre avantage comme ceci:

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

L'idée ici est simple: nous lisons le fichier ligne par ligne, et à partir de chaque ligne, nous créons une chaîne formatée cat "File name.txt", qui est ensuite passée à system().

Et le voici en action:

$ 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

Nous avons donc déjà fait la majeure partie de la tâche - nous avons imprimé tous les fichiers de la liste. Le reste est simple: redirigez la sortie finale vers le fichier avec l' >opérateur dans le fichier récapitulatif.

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