Comment fusionner tous les fichiers (texte) d'un répertoire en un seul?

89

J'ai 14 fichiers faisant tous partie d'un texte. Je voudrais les fusionner en un. Comment faire ça?

Ivan
la source

Réponses:

169

C'est techniquement ce que cat("concaténer") est censé faire, même si la plupart des gens l'utilisent simplement pour sortir des fichiers sur stdout. Si vous lui donnez plusieurs noms de fichiers, il les affichera tous de manière séquentielle et vous pourrez ensuite les rediriger vers un nouveau fichier. dans le cas de tous les fichiers, utilisez-le simplement *(ou /path/to/directory/*si vous n'êtes pas déjà dans le répertoire) et votre shell l'étendra à tous les noms de fichiers

$ cat * > merged-file
Michael Mrozek
la source
15
Attention, votre commande citée ne fera probablement ce que l’affiche veut si elle est numérotée de manière à ce que le shell s’agrandisse *dans un ordre "naturel". Si vous avez "fichier1.txt ... fichier9.txt ... fichier14.txt", cela ne fonctionnera pas car fichier1? .Txt fera le tri entre fichier1.txt et fichier2.txt. Vous devez les renommer "fichier01.txt ... fichier09.txt ... fichier14.txt". Dis echo *si tu n'es pas sur.
Warren Young
2
@Warren: bon point (ou vous pouvez utiliser zsh et définir son numeric_glob_sortoption).
Gilles
2
@ warren-young un commentaire d'avertissement correct et utile. Mais dans mon cas réel, l'ordre ne fait aucune différence (car les fichiers ne contiennent que de simples instructions SQL insérant des enregistrements de données sans dépendance).
Ivan
2
Attention, si le nombre de fichiers dépasse une certaine limite, vous pouvez
générer des
1
@ ARA1307 Seulement si le fichier existe déjà; sinon le glob sera développé avant que le shell n'ouvre le fichier pour y écrire. Bon point dans cette situation cependant
Michael Mrozek
25

Si vos fichiers ne sont pas dans le même répertoire, vous pouvez utiliser la commande find avant la concaténation:

find /path/to/directory/ -name *.csv -print0 | xargs -0 -I file cat file > merged.file

Très utile lorsque vos fichiers sont déjà commandés et que vous souhaitez les fusionner pour les analyser.


Plus portable:

find /path/to/directory/ -name *.csv -exec cat {} + > merged.file

Cela peut ou peut ne pas préserver l'ordre des fichiers.

3nrique0
la source
1
C'est la voie à suivre si vous avez beaucoup de fichiers. Vous évitez une erreur "liste d'arguments trop longue".
Victime vendredi
2
Vous avez besoin de -name "* .csv" au lieu de -name * .csv - sans les guillemets, cela échoue.
Peteris
Le besoin de guillemets dépend de la version de la commande find, spécialement dans find et awk, c'est un problème lorsque vous êtes sur un Mac, les versions des deux programmes sont un peu anciennes. Jusqu'ici sur ubuntu, fedora, debian et CentOS cela a fonctionné sans les guillemets
3nrique0
Je m'attendrais à ce que la version non citée fonctionne quand il n'y a aucun fichier dans le répertoire en cours correspondant au modèle "*.csv", car le shell transmettrait alors le littéral *à find.
RJHunter
9

La commande

$ cat * > merged-file

a en fait l’effet secondaire indésirable d’inclure un «fichier fusionné» dans la concaténation, ce qui crée un fichier vide. Pour résoudre ce problème, écrivez le fichier fusionné dans un autre répertoire.

$ cat * > ../merged-file

ou utilisez une correspondance de modèle qui ignorera le fichier fusionné;

$ cat *.txt > merged-file
Christopher Jones
la source
14
cat * > merged-filefonctionne bien. Les Globs sont traités avant la création du fichier. S'il merged-fileexiste déjà, le catmien détectera qu'il s'agit du fichier de sortie et refusera de le lire. SI le fichier existe déjà ET que vous avez la redirection plus tard dans le pipeline, il ne peut évidemment pas le faire, aussi vous obtenez-vous alors le fichier emballé.
Kevin
catn'a aucun moyen de détecter si le fichier est le fichier de sortie. La redirection se passe dans le shell; catimprime uniquement sur la sortie standard.
bfontaine
8

Comme les autres d'ici disent ... Vous pouvez utiliser cat

Disons que vous avez:

~/file01
~/file02
~/file03
~/file04
~/fileA
~/fileB
~/fileC
~/fileD

Et vous ne souhaitez que file01pour file03et fileAà fileC:

cat ~/file01 ~/file02 ~/file03 ~/fileA ~/fileB ~/fileC > merged-file

Ou, en utilisant une extension par attelle

cat ~/file0{1..3} ~/file{A..C} > merged-file

Ou, en utilisant une extension plus sophistiquée:

cat ~/file{0{1..3},{A..C}} > merged-file

Ou vous pouvez utiliser la forboucle:

for i in file0{1..3} file{A..C}; do cat ~/"$i"; done > merged-file
Florin Idita
la source
1
Notez que la chaîne [01-03]ne fonctionnera pas comme un motif globulant.
Kusalananda
0

Vous pouvez spécifier le patternfichier, puis les fusionner comme suit:

cat *pattern* >> mergedfile
utilisateur182845
la source
0

Une autre option est sed:

sed r 1.txt 2.txt 3.txt > merge.txt 

Ou...

sed h 1.txt 2.txt 3.txt > merge.txt 

Ou...

sed -n p 1.txt 2.txt 3.txt > merge.txt # -n is mandatory here

Ou sans redirection ...

 sed wmerge.txt 1.txt 2.txt 3.txt

Notez que la dernière ligne écrit également merge.txt (pas wmerge.txt!). Vous pouvez utiliser w "merge.txt" pour éviter toute confusion avec le nom du fichier et -n pour une sortie silencieuse.

Bien sûr, vous pouvez également raccourcir la liste de fichiers avec des caractères génériques. Par exemple, dans le cas de fichiers numérotés comme dans les exemples ci-dessus, vous pouvez spécifier la plage avec des accolades de la manière suivante:

sed -n w"merge.txt" {1..3}.txt
Harini
la source