Concatena più file ma includi il nome file come intestazioni di sezione


352

Vorrei concatenare un numero di file di testo in un file di grandi dimensioni nel terminale. So di poterlo fare usando il comando cat. Tuttavia, vorrei che il nome file di ciascun file precedesse il "dump dei dati" per quel file. Qualcuno sa come farlo?

quello che ho attualmente:

file1.txt = bluemoongoodbeer

file2.txt = awesomepossum

file3.txt = hownowbrowncow

cat file1.txt file2.txt file3.txt

output desiderato:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow

sto effettivamente usando uuencode e uudecode per fare qualcosa di simile, non ho bisogno del file leggibile tra di loro, ho solo bisogno del risultato e reindirizzarli a un altro comando

Risposte:


531

Stavo cercando la stessa cosa e ho trovato questo per suggerire:

tail -n +1 file1.txt file2.txt file3.txt

Produzione:

==> file1.txt <==
<contents of file1.txt>

==> file2.txt <==
<contents of file2.txt>

==> file3.txt <==
<contents of file3.txt>

Se è presente un solo file, l'intestazione non verrà stampata. Se si utilizzano i programmi -vdi utilità GNU, è possibile utilizzare per stampare sempre un'intestazione.


2
Funziona anche con la coda GNU (parte di GNU Coreutils).
ArjunShankar,

7
-n +1Opzione fantastica ! Un'alternativa: head -n-0 file1 file2 file3.
Frozen Flame,

2
Funziona alla grande sia con coda BSD che coda GNU su MacOS X. Puoi lasciare fuori lo spazio tra -ne +1, come in -n+1.
vdm,

4
tail -n +1 *era esattamente quello che stavo cercando, grazie!
kR105,

1
funziona su MacOsX 10.14.4sudo ulimit -n 1024; find -f . -name "*.rb" | xargs tail -n+1 > ./source_ruby.txt
kolas

186

Ho usato grep per qualcosa di simile:

grep "" *.txt

Non ti dà un 'intestazione', ma prefigura ogni riga con il nome del file.


10
L'output si interrompe se si *.txtespande in un solo file. A questo proposito, lo consigliereigrep '' /dev/null *.txt
antak il

1
+1 per avermi mostrato un nuovo utilizzo per grep. questo ha soddisfatto perfettamente le mie esigenze. nel mio caso, ogni file conteneva solo una riga, quindi mi ha dato un output ben formattato che era facilmente analizzabile
verboze

9
grepstamperà le intestazioni dei file solo se è presente più di un file. Se si desidera assicurarsi di stampare sempre il percorso del file, utilizzare -H. Se non vuoi usare le intestazioni -h. Si noti inoltre che verrà stampato (standard input)per STDIN.
Jorge Bucaran,

1
Puoi anche usare ag(il cercatore d'argento): per impostazione predefinita, ag . *.txtantepone ogni file con il suo nome e ogni riga con il suo numero.
anol

1
Da notare che passare -na grep produce anche numeri di riga che consentono di scrivere semplici linter con l'individuazione di punti che potrebbero essere rilevati, ad esempio, da emacs.
Depresso

104

Questo dovrebbe fare anche il trucco:

find . -type f -print -exec cat {} \;

Si intende:

find    = linux `find` command finds filenames, see `man find` for more info
.       = in current directory
-type f = only files, not directories
-print  = show found file
-exec   = additionally execute another linux command
cat     = linux `cat` command, see `man cat`, displays file contents
{}      = placeholder for the currently found filename
\;      = tell `find` command that it ends now here

È inoltre possibile combinare ricerche attraverso operatori booleani come -ando -or. find -lsanche bello.


1
Potresti spiegare di più cosa fa questo comando? È esattamente quello di cui avevo bisogno
AAlvz,

4
Questo è il comando find standard di linux. Cerca tutti i file nella directory corrente, stampa il loro nome, quindi per ognuno, gatta il file. Se si omette -print, non verrà stampato il nome file prima di cat.
Maxim_united

17
È inoltre possibile utilizzare -printfper personalizzare l'output. Ad esempio: find *.conf -type f -printf '\n==> %p <==\n' -exec cat {} \;per abbinare l'output ditail -n +1 *
Maxim_united

1
-printf non funziona su Mac, a meno che tu non voglia brew install findutilse poi usi gfindinvece di find.
Matt Fletcher,

1
Se vuoi colori puoi usare quel fatto che findpermette più -execs:find -name '*.conf' -exec printf '\n\e[33;1m%s\e[0m\n' {} \; -exec cat {} \;
banbh

24

Questo dovrebbe fare il trucco:

for filename in file1.txt file2.txt file3.txt; do
    echo "$filename"
    cat "$filename"
done > output.txt

o per fare questo in modo ricorsivo per tutti i file di testo:

find . -type f -name '*.txt' -print | while read filename; do
    echo "$filename"
    cat "$filename"
done > output.txt

1
non ha funzionato. Ho appena scritto un codice awk davvero brutto: per me in $ listoffiles do awk '{print FILENAME, $ 0, $ 1, $ 2, $ 3, $ 4, $ 5, $ 6, $ 7, $ 8, $ 9, $ 10, $ 11}' $ i >> concat.txt fatto
Nick,

2
... ti interessa elaborare? È semplice quanto il codice bash diventa.
Chris Eberle,

@Nick: la tua riga awk non dovrebbe nemmeno funzionare, considerando che $0è l'intera riga, quindi hai effettivamente ripetuto le colonne lì dentro ...
Chris Eberle

@Nick: soluzione Nifty altrimenti :)
Chris Eberle

@ Chris: sì, ma è molto più brutto di quanto vorrei che fosse. Forse il tuo codice non funzionava per me perché sto usando >> per catturare lo stdout?
Nick,

17

Avevo una serie di file che terminavano in stats.txt che volevo concatenare con i nomi dei file.

Ho fatto quanto segue e quando c'è più di un file, il comando "più" include il nome del file come intestazione.

more *stats.txt > stats.txt

o per un caso generale

more FILES_TO_CONCAT > OUTPUT_FILE

6
more <FILES> | cat
Acumenus,

15
find . -type f -print0 | xargs -0 -I % sh -c 'echo %; cat %'

Questo stamperà il nome file completo (incluso il percorso), quindi il contenuto del file. È anche molto flessibile, dato che puoi usare -name "expr" per il comando find ed eseguire tutti i comandi che desideri sui file.


1
È anche abbastanza semplice da abbinare grep. Da utilizzare con bash:find . -type f -print | grep PATTERN | xargs -n 1 -I {} -i bash -c 'echo ==== {} ====; cat {}; echo'
dojuba

5

Mi piace questa opzione

for x in $(ls ./*.php); do echo $x; cat $x | grep -i 'menuItem'; done

L'output è simile al seguente:

./debug-things.php
./Facebook.Pixel.Code.php
./footer.trusted.seller.items.php
./GoogleAnalytics.php
./JivositeCode.php
./Live-Messenger.php
./mPopex.php
./NOTIFICATIONS-box.php
./reviewPopUp_Frame.php
            $('#top-nav-scroller-pos-<?=$active**MenuItem**;?>').addClass('active');
            gotTo**MenuItem**();
./Reviews-Frames-PopUps.php
./social.media.login.btns.php
./social-side-bar.php
./staticWalletsAlerst.php
./tmp-fix.php
./top-nav-scroller.php
$active**MenuItem** = '0';
        $active**MenuItem** = '1';
        $active**MenuItem** = '2';
        $active**MenuItem** = '3';
./Waiting-Overlay.php
./Yandex.Metrika.php

4

Ecco come gestisco normalmente la formattazione in questo modo:

for i in *; do echo "$i"; echo ; cat "$i"; echo ; done ;

Generalmente convoglio il gatto in un grep per informazioni specifiche.


3
Stai attento qui. for i in *non includerà le sottodirectory.
Acumenus,


3

puoi usare questo semplice comando invece di usare un ciclo for,

ls -ltr | awk '{print $9}' | xargs head

3

Se ti piacciono i colori, prova questo:

for i in *; do echo; echo $'\e[33;1m'$i$'\e[0m'; cat $i; done | less -R

o:

tail -n +1 * | grep -e $ -e '==.*'

oppure: (con il pacchetto 'multitail' installato)

multitail *

1
Per motivi di colore che evidenziano il nome file:find . -type f -name "*.txt" | xargs -I {} bash -c "echo $'\e[33;1m'{}$'\e[0m';cat {}"
MediaVince

3

Se tutti i file hanno lo stesso nome o possono essere abbinati find, puoi fare (ad es.):

find . -name create.sh | xargs tail -n +1

per trovare, mostrare il percorso di e cat ogni file.


2

Ecco un modo davvero semplice. Hai detto che vuoi cat, il che implica che vuoi visualizzare l'intero file. Ma devi anche stampare il nome del file.

Prova questo

head -n99999999 * o head -n99999999 file1.txt file2.txt file3.txt

spero che aiuti


4
sarebbe una sintassi più pulita head -n -0 file.txt file2.txt file3.txt. Funziona headcon GNU coreutils
doubleDown,

1

Questo metodo stampa il nome del file e quindi il contenuto del file:

tail -f file1.txt file2.txt

Produzione:

==> file1.txt <==
contents of file1.txt ...
contents of file1.txt ...

==> file2.txt <==
contents of file2.txt ...
contents of file2.txt ...

3
L' -fopzione è utile se si desidera tenere traccia di un file che viene scritto, ma non proprio nell'ambito di applicazione di ciò che l'OP ha chiesto.
Tripleee

1

Se vuoi sostituire quei brutti ==> <== con qualcos'altro

tail -n +1 *.txt | sed -e 's/==>/\n###/g' -e 's/<==/###/g' >> "files.txt"

spiegazione:

tail -n +1 *.txt - genera tutti i file nella cartella con intestazione

sed -e 's/==>/\n###/g' -e 's/<==/###/g'- sostituisci ==>con la nuova linea + ### e <==con solo ###

>> "files.txt" - output tutto su un file



0

Se vuoi il risultato nello stesso formato dell'output desiderato, puoi provare:

for file in `ls file{1..3}.txt`; \
do echo $file | cut -d '.' -f 1; \ 
cat $file  ; done;

Risultato:

file1
bluemoongoodbeer
file2
awesomepossum
file3
hownowbrowncow

Puoi mettere echo -eprima e dopo il taglio in modo da avere anche la spaziatura tra le linee:

$ for file in `ls file{1..3}.txt`; do echo $file | cut -d '.' -f 1; echo -e; cat $file; echo -e  ; done;

Risultato:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow

Spiegazione: il forciclo passa attraverso l'elenco lsrisultante dal comando. $ ls file{1..3}.txtRisultato: file1.txt file2.txt file3.txtogni iterazione sarà echola $filestringa, quindi verrà reindirizzata a un cutcomando in cui ho usato .come separatore di campo che rompe fileX.txt in due pezzi e stampa il campo1 (field2 è il txt) Il resto dovrebbe essere chiaro
Fekete Sumér

0
  • AIX 7.1 ksh

... glomming su coloro che hanno già menzionato testa opere per alcuni di noi:

$ r head
head file*.txt
==> file1.txt <==
xxx
111

==> file2.txt <==
yyy
222
nyuk nyuk nyuk

==> file3.txt <==
zzz
$

Il mio bisogno è leggere la prima riga; come notato, se vuoi più di 10 righe, dovrai aggiungere opzioni (head -9999, etc).

Ci scusiamo per la pubblicazione di un commento derivato; Non ho credito stradale sufficiente per commentare / aggiungere al commento di qualcuno.


-1

Per risolvere questi compiti di solito uso il seguente comando:

$ cat file{1..3}.txt >> result.txt

È un modo molto conveniente per concatenare i file se il numero di file è piuttosto elevato.


1
Ma questo non risponde alla domanda del PO.
kvantour,

-3

Per prima cosa ho creato ogni file: echo 'information'> file1.txt per ogni file [123] .txt.

Quindi ho stampato ogni file per assicurarmi che le informazioni fossero corrette: tail file? .Txt

Quindi ho fatto questo: tail file? .Txt >> Mainfile.txt. Ciò ha creato Mainfile.txt per archiviare le informazioni in ciascun file in un file principale.

cat Mainfile.txt ha confermato che andava bene.

==> file1.txt <== bluemoongoodbeer

==> file2.txt <== awesomepossum

==> file3.txt <== hownowbrowncow

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.