Come unire tutti i file (di testo) in una directory in uno?


89

Ho 14 file che fanno tutti parte di un testo. Mi piacerebbe unirli in uno. Come farlo?

Risposte:


169

Questo è tecnicamente ciò che cat("concatenare") dovrebbe fare, anche se la maggior parte delle persone lo usa solo per inviare file a stdout. Se gli dai più nomi di file, li genererà tutti in sequenza, quindi puoi reindirizzarli in un nuovo file; nel caso di tutti i file basta usare *(o /path/to/directory/*se non ci si trova già nella directory) e la shell lo espanderà in tutti i nomi dei file

$ cat * > merged-file

15
Attenzione che il tuo comando citato probabilmente farà ciò che vuole il poster solo se sono numerati in modo tale che la shell si espanda *in un ordine "naturale". Se hai "file1.txt ... file9.txt ... file14.txt" non funzionerà perché file1? .Txt ordinerà tra file1.txt e file2.txt. Dovresti rinominarli in "file01.txt ... file09.txt ... file14.txt". Di ' echo *se non sei sicuro.
Warren Young,

2
@Warren: buon punto (oppure puoi usare zsh e impostare la sua numeric_glob_sortopzione).
Gilles,

2
@ warren-young un corretto, utile commento di avvertimento. Ma nel mio caso reale l'ordine non fa differenza (perché i file contengono solo semplici istruzioni SQL che inseriscono record di dati che non hanno dipendenze).
Ivan,

2
Attenzione, se il conteggio dei file supera un certo limite, è possibile eseguire errori come - / bin / cat: elenco degli argomenti troppo lungo
Nupur

1
@ ARA1307 Solo se il file esiste già; altrimenti il ​​glob verrà espanso prima che la shell apra il file per scrivergli. Un buon punto in quella situazione però
Michael Mrozek

25

Se i tuoi file non si trovano nella stessa directory, puoi utilizzare il comando find prima della concatenazione:

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

Molto utile quando i tuoi file sono già ordinati e vuoi unirli per analizzarli.


Più facilmente:

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

Questo può o meno conservare l'ordine dei file.


1
Questa è la strada da percorrere se hai molti file. Si evita un errore "Elenco argomenti troppo lungo".
Мати Тернер,

2
È necessario -name "* .csv" anziché -name * .csv - senza virgolette non riesce.
Peteris,

La necessità di virgolette dipende dalla versione del comando find, specialmente in find e awk è un problema quando sei su un mac, le versioni di entrambi i programmi sono un po 'vecchie. Finora su Ubuntu, Fedora, Debian e CentOS ha funzionato senza intoppi senza virgolette
3nrique0

Mi aspetto la versione non quotato al lavoro quando non ci sono file nella directory corrente che corrispondono al modello "*.csv", in quanto il guscio sarebbe poi passare il letterale *a find.
RJHunter,


9

Il comando

$ cat * > merged-file

in realtà ha l'effetto collaterale indesiderato di includere "file unito" nella concatenazione, creando un file run-away. Per ovviare a questo, scrivere il file unito in una directory diversa;

$ cat * > ../merged-file

oppure usa una corrispondenza di pattern che ignorerà il file unito;

$ cat *.txt > merged-file

14
cat * > merged-filefunziona bene. I globi vengono elaborati prima della creazione del file. Se merged-fileesiste già cat(almeno il mio) rileverà che si tratta del file di output e rifiuterà di leggerlo. SE il file esiste già E hai il reindirizzamento più avanti nella pipeline, quindi ovviamente non può farlo, quindi solo e solo allora ottieni il file in fuga.
Kevin,

catnon ha modo di rilevare se il file è quello di output. Il reindirizzamento avviene nella shell; catstampa solo su stdout.
bfontaine,

8

Come gli altri da qui dicono ... Puoi usare cat

Diciamo che hai:

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

E vuoi solo file01a file03e fileAa fileC:

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

Oppure, usando l'espansione del controvento:

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

Oppure, usando l'espansione del supporto più elaborato:

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

Oppure puoi usare forloop:

for i in file0{1..3} file{A..C}; do cat ~/"$i"; done > merged-file

1
Si noti che la stringa [01-03]non funzionerà come un modello globbing.
Kusalananda

0

È possibile specificare il patterndi un file, quindi unirli tutti come segue:

cat *pattern* >> mergedfile

0

Un'altra opzione è sed:

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

O...

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

O...

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

O senza reindirizzamento ...

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

Nota che l'ultima riga scrive anche merge.txt (non wmerge.txt!). È possibile utilizzare w "merge.txt" per evitare confusione con il nome del file e -n per l'output silenzioso.

Naturalmente, puoi anche abbreviare l'elenco dei file con i caratteri jolly. Ad esempio, nel caso di file numerati come negli esempi precedenti, è possibile specificare l'intervallo con parentesi graffe in questo modo:

sed -n w"merge.txt" {1..3}.txt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.