Menggabungkan banyak file tetapi menyertakan nama file sebagai header bagian

352

Saya ingin menggabungkan beberapa file teks menjadi satu file besar di terminal. Saya tahu saya bisa melakukan ini menggunakan perintah cat. Namun, saya ingin nama file dari setiap file untuk mendahului "dump data" untuk file itu. Adakah yang tahu bagaimana melakukan ini?

apa yang saya miliki saat ini:

file1.txt = bluemoongoodbeer

file2.txt = awesomepossum

file3.txt = hownowbrowncow

cat file1.txt file2.txt file3.txt

output yang diinginkan:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow
Nick
sumber
saya sebenarnya menggunakan uuencode & uudecode untuk melakukan sesuatu yang serupa, saya tidak perlu peralihan file yang dapat dibaca, hanya perlu hasilnya dan pipa mereka ke perintah lain lagi
2
unix.stackexchange.com/questions/12342/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功

Jawaban:

531

Sedang mencari hal yang sama, dan menemukan ini menyarankan:

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

Keluaran:

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

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

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

Jika hanya ada satu file maka header tidak akan dicetak. Jika menggunakan utils GNU, Anda dapat menggunakannya -vuntuk selalu mencetak header.

DS.
sumber
2
Ini bekerja dengan ekor GNU (bagian dari GNU Coreutils) juga.
ArjunShankar
7
Mengagumkan -n +1pilihan! Alternatif: head -n-0 file1 file2 file3.
Api Beku
2
Bekerja sangat baik dengan ekor BSD dan ekor GNU pada MacOS X. Anda dapat meninggalkan ruang di antara -ndan +1, seperti pada -n+1.
vdm
4
tail -n +1 *sebenarnya adalah yang saya cari, terima kasih!
kR105
1
bekerja pada MacOSX 10.14.4sudo ulimit -n 1024; find -f . -name "*.rb" | xargs tail -n+1 > ./source_ruby.txt
Kolas
186

Saya menggunakan grep untuk sesuatu yang serupa:

grep "" *.txt

Itu tidak memberi Anda 'header', tetapi awalan setiap baris dengan nama file.

Theo
sumber
10
Output rusak jika *.txtdiperluas hanya ke satu file. Dalam hal ini, saya akan menyarankangrep '' /dev/null *.txt
antak
1
+1 untuk menunjukkan kepada saya penggunaan baru untuk grep. ini memenuhi kebutuhan saya dengan sempurna. dalam kasus saya, setiap file hanya berisi satu baris, jadi itu memberi saya output yang diformat rapi yang mudah
diurai
9
grephanya akan mencetak header file jika ada lebih dari satu file. Jika Anda ingin selalu memastikan jalur file, gunakan -H. Jika Anda tidak ingin header digunakan -h. Juga perhatikan itu akan mencetak (standard input)untuk STDIN.
Jorge Bucaran
1
Anda juga dapat menggunakan ag(pencari perak): secara default, ag . *.txtawalan setiap file dengan namanya, dan setiap baris dengan nomornya.
anol
1
Sebagai catatan, meneruskan -nke grep juga menghasilkan nomor baris yang memungkinkan Anda untuk menulis linter sederhana dengan penentuan yang dapat diambil oleh, misalnya, emacs.
DepressedDaniel
104

Ini harus melakukan triknya juga:

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

Cara:

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

Anda selanjutnya dapat menggabungkan pencarian melalui operator boolean seperti -andatau -or. find -lsitu bagus juga.

Maxim_united
sumber
1
Bisakah Anda menjelaskan lebih lanjut apa yang dilakukan perintah ini? Persis seperti yang
kubutuhkan
4
Ini adalah perintah pencarian standar linux. Itu mencari semua file di direktori saat ini, mencetak nama mereka, lalu untuk masing-masing, kucing file. Menghilangkan -printtidak akan mencetak nama file sebelum cat.
Maxim_united
17
Anda juga dapat menggunakan -printfuntuk menyesuaikan output. Misalnya: find *.conf -type f -printf '\n==> %p <==\n' -exec cat {} \;untuk mencocokkan keluarantail -n +1 *
Maxim_united
1
-printf tidak bekerja pada mac, kecuali jika Anda ingin brew install findutilsdan kemudian menggunakan gfindbukannya find.
Matt Fletcher
1
Jika Anda ingin warna, Anda dapat menggunakan fakta yang findmemungkinkan banyak -execs:find -name '*.conf' -exec printf '\n\e[33;1m%s\e[0m\n' {} \; -exec cat {} \;
banbh
24

Ini harus melakukan trik:

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

atau melakukan ini untuk semua file teks secara rekursif:

find . -type f -name '*.txt' -print | while read filename; do
    echo "$filename"
    cat "$filename"
done > output.txt
Chris Eberle
sumber
1
tidak bekerja Saya baru saja menulis beberapa kode awk yang sangat jelek: untuk saya di $ listoffiles do awk '{print FILENAME, $ 0, $ 1, $ 2, $ 3, $ 4, $ 5, $ 6, $ 7, $ 8, $ 9, $ 10, $ 11}' $ i >> concat.txt selesai
Nick
2
... peduli untuk menjelaskan? Itu sesederhana kode bash.
Chris Eberle
@Nick: Baris awk Anda seharusnya tidak berfungsi, mengingat itu $0adalah seluruh baris, jadi Anda sebenarnya punya kolom berulang di sana ...
Chris Eberle
@Nick: Solusi bagus kalau tidak :)
Chris Eberle
@ Chris: ya, tapi jauh lebih jelek dari yang saya inginkan. Mungkin kode Anda tidak berfungsi untuk saya karena saya menggunakan >> untuk menangkap stdout?
Nick
17

Saya memiliki serangkaian file yang berakhir dengan stats.txt yang ingin saya gabungkan dengan nama file.

Saya melakukan yang berikut dan ketika ada lebih dari satu file, perintah "lebih" termasuk nama file sebagai header.

more *stats.txt > stats.txt

atau untuk kasus umum

more FILES_TO_CONCAT > OUTPUT_FILE
Steinfadt
sumber
6
more <FILES> | cat
Acumenus
15
find . -type f -print0 | xargs -0 -I % sh -c 'echo %; cat %'

Ini akan mencetak nama file lengkap (termasuk jalur), lalu isi file. Ini juga sangat fleksibel, karena Anda dapat menggunakan -nama "expr" untuk perintah find, dan menjalankan perintah sebanyak yang Anda suka pada file.

kevinf
sumber
1
Ini juga cukup mudah untuk digabungkan grep. Untuk digunakan dengan bash:find . -type f -print | grep PATTERN | xargs -n 1 -I {} -i bash -c 'echo ==== {} ====; cat {}; echo'
dojuba
5

Saya suka opsi ini

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

Output terlihat seperti ini:

./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
ch3ll0v3k
sumber
4

Ini adalah cara saya biasanya menangani pemformatan seperti itu:

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

Saya biasanya menyalurkan kucing ke grep untuk mendapatkan informasi spesifik.

MorpheousMarty
sumber
3
Hati-hati di sini. for i in *tidak akan menyertakan subdirektori.
Acumenus
4

Dan solusi awk yang hilang adalah:

$ awk '(FNR==1){print ">> " FILENAME " <<"}1' *
Kvantour
sumber
Terima kasih atas jawaban Anda. Bisakah Anda menjelaskan arti 1di akhir ekspresi?
bwangel
1
Terima kasih. Anda dapat melihat apa arti 1 di akhir naskah awk
kvantour
3

Anda dapat menggunakan perintah sederhana ini alih-alih menggunakan for loop,

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

Jika Anda suka warna, coba ini:

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

atau:

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

atau: (dengan paket 'multitail' diinstal)

multitail *
sja
sumber
1
Demi warna yang menyoroti nama file:find . -type f -name "*.txt" | xargs -I {} bash -c "echo $'\e[33;1m'{}$'\e[0m';cat {}"
MediaVince
3

Jika semua file memiliki nama yang sama atau dapat dicocokkan find, Anda dapat melakukan (mis.):

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

untuk menemukan, tunjukkan path dan cat setiap file.

drkvogel
sumber
2

Ini cara yang sangat sederhana. Anda bilang ingin cat, yang berarti Anda ingin melihat seluruh file. Tetapi Anda juga perlu nama file dicetak.

Coba ini

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

Semoga itu bisa membantu

Trey Brister
sumber
4
sintaks pembersih akan head -n -0 file.txt file2.txt file3.txt. Bekerja untuk headdalam GNU
coreutils
1

Metode ini akan mencetak nama file dan kemudian isi file:

tail -f file1.txt file2.txt

Keluaran:

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

==> file2.txt <==
contents of file2.txt ...
contents of file2.txt ...
serenesat
sumber
3
Ini -fberguna jika Anda ingin melacak file yang sedang ditulis, tetapi tidak benar-benar dalam ruang lingkup apa yang diminta OP.
tripleee
1

Jika Anda ingin mengganti yang jelek ==> <== dengan yang lain

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

penjelasan:

tail -n +1 *.txt - Keluarkan semua file dalam folder dengan header

sed -e 's/==>/\n###/g' -e 's/<==/###/g'- ganti ==>dengan baris baru + ### dan <==hanya dengan ###

>> "files.txt" - Keluarkan semua ke file

boroboris
sumber
0
find . -type f -exec cat {} \; -print
pengguna5689319
sumber
0

Jika Anda ingin hasil dalam format yang sama dengan output yang Anda inginkan, Anda dapat mencoba:

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

Hasil:

file1
bluemoongoodbeer
file2
awesomepossum
file3
hownowbrowncow

Anda dapat meletakkan echo -esebelum dan sesudah pemotongan sehingga Anda memiliki jarak antar garis juga:

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

Hasil:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow
Fekete Sumér
sumber
Penjelasan: forloop melewati daftar lsperintah yang dihasilkan. $ ls file{1..3}.txtHasil: file1.txt file2.txt file3.txtsetiap iterasi akan echomenjadi $filestring kemudian disalurkan ke cutperintah di mana saya digunakan .sebagai pemisah bidang yang memecah fileX.txt menjadi dua bagian dan mencetak bidang1 (bidang2 adalah txt) Selebihnya harus jelas
Fekete Sumér
0
  • AIX 7.1 ksh

... memelototi mereka yang sudah menyebutkan kepala bekerja untuk sebagian dari kita:

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

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

==> file3.txt <==
zzz
$

Kebutuhan saya adalah membaca baris pertama; seperti yang disebutkan, jika Anda ingin lebih dari 10 baris, Anda harus menambahkan opsi (head -9999, dll).

Maaf telah memposting komentar turunan; Saya tidak memiliki kredibilitas jalanan yang memadai untuk berkomentar / menambahkan komentar seseorang.

JustinKaisse
sumber
-1

Untuk menyelesaikan tugas ini saya biasanya menggunakan perintah berikut:

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

Ini adalah cara yang sangat mudah untuk menggabungkan file jika jumlah file cukup besar.

Igor
sumber
1
Tetapi ini tidak menjawab pertanyaan OP.
kvantour
-3

Pertama saya membuat setiap file: echo 'informasi'> file1.txt untuk setiap file [123] .txt.

Lalu saya mencetak setiap file untuk memastikan informasi benar: file ekor? .Txt

Lalu saya melakukan ini: file ekor? .Txt >> Mainfile.txt. Ini menciptakan Mainfile.txt untuk menyimpan informasi di setiap file menjadi file utama.

cat Mainfile.txt mengonfirmasi bahwa itu baik-baik saja.

==> file1.txt <== bluemoongoodbeer

==> file2.txt <== awesomepossum

==> file3.txt <== hownowbrowncow

John Ray
sumber