Come aggiungere il contenuto di più file in un unico file


174

Voglio copiare il contenuto di cinque file in un file così com'è. Ho provato a farlo usando cp per ogni file. Ma questo sovrascrive il contenuto copiato dal file precedente. Ho anche provato

paste -d "\n" 1.txt 0.txt

e non ha funzionato.

Voglio che il mio script aggiunga la nuova riga alla fine di ogni file di testo.

per esempio. File 1.txt, 2.txt, 3.txt. Inserisci il contenuto di 1,2,3 in 0.txt

Come lo faccio ?



Risposte:


308

È necessario il catcomando (abbreviato per concatenare), con il reindirizzamento della shell ( >) nel file di output

cat 1.txt 2.txt 3.txt > 0.txt

8
dovrebbe essere >> giusto? e anche perché c'è una riga prima di tutto il testo nel mio file 0.txt?
Steam

1
volevi preservare il contenuto di 0.txt?
visto il

13
@blasto dipende. Dovresti usare >>per aggiungere un file su un altro, dove > sovrascrive il file di output con tutto ciò che è diretto in esso. Per quanto riguarda la nuova riga, esiste una nuova riga come primo carattere nel file 1.txt? Puoi scoprirlo usando od -ce vedendo se il primo personaggio è a \n.
radical7,

1
@ Grazie radical7. In realtà, i miei file sono come foo_1, foo_2, foo_3. Ho provato a modificare il codice come - cat "$ nomefile _" {1,2,3} ". Txt", ma non ha funzionato.
Steam

1
@blasto Stai decisamente andando nella direzione giusta. Bash sicuramente accetta il modulo {...}per la corrispondenza dei nomi dei file, quindi forse le virgolette hanno incasinato un po 'le cose nel tuo script? Cerco sempre di lavorare con cose come questa usando lsin una shell. Quando ottengo il comando giusto, lo taglio e incolla in uno script così com'è. Potresti anche trovare -xutile l' opzione nei tuoi script: farà eco ai comandi espansi nello script prima dell'esecuzione.
radical7,

97

Un'altra opzione, per quelli di voi che ancora inciampano in questo post come ho fatto io, è usare find -exec:

find . -type f -name '*.txt' -exec cat {} + >> output.file

Nel mio caso, avevo bisogno di un'opzione più robusta che avrebbe esaminato più sottodirectory, quindi ho scelto di utilizzare find. Abbattendo:

find .

Cerca nella directory di lavoro corrente.

-type f

Interessato solo ai file, non alle directory, ecc.

-name '*.txt'

Elimina il risultato impostato per nome

-exec cat {} +

Eseguire il comando cat per ciascun risultato. "+" significa che catviene generata solo 1 istanza di (thx @gniourf_gniourf)

 >> output.file

Come spiegato in altre risposte, aggiungi il contenuto incluso alla fine di un file di output.


10
Ci sono molti difetti in questa risposta. Innanzitutto, il carattere jolly *.txtdeve essere citato (altrimenti, l'intero findcomando, come scritto, è inutile). Un altro difetto deriva da un grave malinteso: il comando che viene eseguito non lo è cat >> 0.txt {} , ma cat {}. Il tuo comando è in effetti equivalente a { find . -type f -name *.txt -exec cat '{}' \; ; } >> 0.txt(ho aggiunto il raggruppamento in modo da capire cosa sta realmente accadendo). Un altro difetto è che findsta per trovare il file 0.txte catsi lamenterà dicendo che il file di input è un file di output .
gniourf_gniourf

Grazie per le correzioni. Il mio caso era un po 'diverso e non avevo pensato ad alcuni di quei gotcha applicati a questo caso.
mopo922,

Dovresti mettere >> output.filealla fine del tuo comando, in modo da non indurre nessuno (incluso te stesso) a pensare che findverrà eseguito cat {} >> output.fileper ogni file trovato.
gniourf_gniourf

Iniziando a sembrare davvero bello! Un ultimo suggerimento: utilizzare -exec cat {} +invece di -exec cat {} \;, in modo che catvenga generata solo un'istanza di con diversi argomenti ( +è specificato da POSIX ).
gniourf_gniourf

3
Buona risposta e avvertimento - Ho modificato il mio in: find . -type f -exec cat {} + >> outputfile.txte non riuscivo a capire perché il mio file di output non smettesse di crescere nei concerti anche se la directory era solo 50 mega. È perché ho continuato ad aggiungere outputfile.txt a se stesso! Quindi assicurati di nominare quel file correttamente o posizionarlo in un'altra directory per evitarlo.
flusso è finito il

43

se hai un certo tipo di output, fai qualcosa del genere

cat /path/to/files/*.txt >> finalout.txt

1
Tieni presente che stai perdendo la possibilità di mantenere l'ordine di fusione. Questo può influire su di te se hai i tuoi file nominati, ad es. file_1,, file_2... file_11, a causa dell'ordine naturale di ordinamento dei file.
emix

16

Se tutti i tuoi file si trovano in un'unica directory, puoi semplicemente farlo

cat * > 0.txt

I file 1.txt, 2.txt, .. andranno in 0.txt


Già risposto da Eswar. Tieni presente che stai perdendo la possibilità di mantenere l'ordine di fusione. Questo può influire su di te se hai i tuoi file nominati, ad es. file_1,, file_2... file_11, a causa dell'ordine naturale di ordinamento dei file.
emix

10
for i in {1..3}; do cat "$i.txt" >> 0.txt; done

Ho trovato questa pagina perché dovevo unire 952 file in uno solo. Ho scoperto che funziona molto meglio se hai molti file. Questo farà un ciclo per tutti i numeri di cui hai bisogno e cat ciascuno usando >> per aggiungere alla fine di 0.txt.


potresti usare l'espansione di parentesi graffe in bash per scrivere cat {1,2,3} .txt >> 0.txt
mcheema

9

Se tutti i tuoi file hanno un nome simile, potresti semplicemente fare:

cat *.log >> output.log

5

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 -nper 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

4

se i tuoi file contengono intestazioni e desideri rimuoverli nel file di output, puoi utilizzare:

for f in `ls *.txt`; do sed '2,$!d' $f >> 0.out; done

3

Se il file originale contiene caratteri non stampabili, andranno persi quando si utilizza il comando cat. Usando 'cat -v', i non stampabili verranno convertiti in stringhe di caratteri visibili, ma il file di output non conterrebbe ancora i caratteri non stampabili effettivi nel file originale. Con un numero limitato di file, un'alternativa potrebbe essere quella di aprire il primo file in un editor (ad es. Vim) che gestisce i caratteri non stampabili. Passa quindi alla fine del file e inserisci ": r second_file_name". Verrà inserito il secondo file, inclusi i caratteri non stampabili. Lo stesso potrebbe essere fatto per file aggiuntivi. Quando tutti i file sono stati letti, inserisci ": w". Il risultato finale è che il primo file conterrà ora ciò che ha fatto originariamente, oltre al contenuto dei file che sono stati letti.


Questo non è molto scriptabile.
FKEinternet,

1

Se vuoi aggiungere il contenuto di 3 file in un unico file, allora il seguente comando sarà una buona scelta:

cat file1 file2 file3 | tee -a file4 > /dev/null

Combinerà il contenuto di tutti i file in file4, generando l'output della console /dev/null.

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.