ต่อกันหลายไฟล์ แต่รวมชื่อไฟล์เป็นส่วนหัว


354

ฉันต้องการเชื่อมไฟล์ข้อความหลายไฟล์เป็นไฟล์ขนาดใหญ่หนึ่งไฟล์ในเทอร์มินัล ฉันรู้ว่าฉันสามารถทำได้โดยใช้คำสั่ง cat อย่างไรก็ตามฉันต้องการให้ชื่อไฟล์ของแต่ละไฟล์นำหน้า "data dump" สำหรับไฟล์นั้น ใครรู้วิธีการทำเช่นนี้?

สิ่งที่ฉันมีอยู่ในปัจจุบัน:

file1.txt = bluemoongoodbeer

file2.txt = awesomepossum

file3.txt = hownowbrowncow

cat file1.txt file2.txt file3.txt

ผลลัพธ์ที่ต้องการ:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow

จริง ๆ แล้วฉันใช้ uuencode & uudecode เพื่อทำสิ่งที่คล้ายกันฉันไม่ต้องการไฟล์ที่อ่านได้ในระหว่างนั้นเพียงต้องการผลลัพธ์และ

คำตอบ:


532

กำลังมองหาสิ่งเดียวกันและพบสิ่งนี้เพื่อแนะนำ:

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

เอาท์พุท:

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

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

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

หากมีเพียงไฟล์เดียวส่วนหัวจะไม่ถูกพิมพ์ หากใช้ GNU utils คุณสามารถใช้-vพิมพ์หัวข้อได้ตลอดเวลา


2
ใช้ได้กับหาง GNU (ส่วนหนึ่งของ CoreUils GNU) เช่นกัน
ArjunShankar

8
-n +1ตัวเลือกที่ยอดเยี่ยม! ทางเลือก: head -n-0 file1 file2 file3.
Frozen Flame

3
ใช้งานได้ดีกับทั้งหาง BSD และหาง GNU บน MacOS X. คุณสามารถออกจากช่องว่างระหว่าง-nและในขณะที่+1 -n+1
vdm

4
tail -n +1 *เป็นสิ่งที่ฉันกำลังมองหาขอบคุณ!
kR105

1
ใช้งานได้กับ MacOsX 10.14.4sudo ulimit -n 1024; find -f . -name "*.rb" | xargs tail -n+1 > ./source_ruby.txt
kolas

187

ฉันใช้ grep สำหรับสิ่งที่คล้ายกัน:

grep "" *.txt

มันไม่ได้ให้ 'ส่วนหัว' แต่นำหน้าทุกบรรทัดด้วยชื่อไฟล์


10
เอาต์พุตหยุดพักหาก*.txtขยายเป็นไฟล์เดียวเท่านั้น ในเรื่องนี้ฉันแนะนำgrep '' /dev/null *.txt
antak

1
+1 สำหรับแสดงให้ฉันเห็นการใช้งานใหม่สำหรับ grep ตรงกับความต้องการของฉันอย่างสมบูรณ์แบบ ในกรณีของฉันแต่ละไฟล์มีเพียงหนึ่งบรรทัดดังนั้นมันจึงให้ผลลัพธ์ที่จัดรูปแบบเรียบร้อยที่สามารถแยกวิเคราะห์ได้ง่าย
verboze

9
grepจะพิมพ์เฉพาะส่วนหัวของไฟล์หากมีมากกว่าหนึ่งไฟล์ หากคุณต้องการพิมพ์พา ธ ของไฟล์ให้ใช้-Hเสมอ -hหากคุณไม่ต้องการใช้ส่วนหัว ยังทราบว่ามันจะพิมพ์(standard input)สำหรับ STDIN
Jorge Bucaran

1
นอกจากนี้คุณยังสามารถใช้ag(ผู้ค้นหาซิลเวอร์): โดยค่าเริ่มต้นag . *.txtนำหน้าแต่ละไฟล์ด้วยชื่อของมันและแต่ละบรรทัดที่มีหมายเลข
anol

1
การทราบ-nถึงการส่งผ่านgrep ยังทำให้ได้หมายเลขบรรทัดที่อนุญาตให้คุณเขียน linters ง่าย ๆ ด้วยการหาตำแหน่งที่สามารถหยิบขึ้นมาได้เช่น emacs
DepaniDaniel

105

สิ่งนี้ควรทำเคล็ดลับเช่นกัน:

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

หมายถึง:

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

นอกจากนี้คุณยังสามารถรวมการค้นหารางประกอบการบูลีนชอบหรือ-and ก็ดีเหมือนกัน-orfind -ls


1
คุณช่วยอธิบายเพิ่มเติมว่าคำสั่งนี้ทำอะไรได้บ้าง? เป็นสิ่งที่ฉันต้องการ
AAlvz

5
นี่คือคำสั่งค้นหามาตรฐานของ linux มันค้นหาไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันพิมพ์ชื่อของพวกเขาแล้วแต่ละไฟล์แมวไฟล์ ถนัดจะไม่พิมพ์ชื่อไฟล์ก่อนที่-print cat
Maxim_united

18
นอกจากนี้คุณยังสามารถใช้-printfในการปรับแต่งการส่งออก ตัวอย่างเช่น: find *.conf -type f -printf '\n==> %p <==\n' -exec cat {} \;เพื่อจับคู่ผลลัพธ์ของtail -n +1 *
Maxim_united

1
-printf ไม่ทำงานบน Mac, ถ้าคุณต้องการbrew install findutilsแล้วใช้แทนgfind find
Matt Fletcher

2
ถ้าคุณต้องการสีคุณสามารถใช้ความจริงนั้นที่findอนุญาตให้หลาย-execs:find -name '*.conf' -exec printf '\n\e[33;1m%s\e[0m\n' {} \; -exec cat {} \;
banbh

24

สิ่งนี้ควรทำเคล็ดลับ:

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

หรือทำสิ่งนี้สำหรับไฟล์ข้อความทั้งหมดซ้ำ:

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

1
ไม่ทำงาน ฉันเพิ่งเขียนรหัส awk ที่น่าเกลียดจริงๆ: สำหรับ i ใน $ listoffiles do awk '{print FILENAME, $ 0, $ 1, $ 2, $ 3, $ 3, $ 4, $ 5, $ 6, $ 7, $ 8, $ 10, $ 11}' $ i >> concat.txt เรียบร้อยแล้ว
Nick

2
... สนใจที่จะทำอย่างละเอียด? นั่นเป็นเรื่องง่ายพอ ๆ กับการใช้รหัสทุบตี
Chris Eberle

@ Nick: บรรทัด awk ของคุณไม่ควรแม้แต่ทำงานพิจารณาว่า$0เป็นสายทั้งหมดเพื่อให้คุณได้มีการทำซ้ำจริงคอลัมน์ในมี ...
คริส Eberle

วิธีการแก้ปัญหา Nifty มิฉะนั้น :): @ Nick
คริส Eberle

@ Chris: ใช่ แต่มันน่าเกลียดกว่าที่ฉันต้องการ บางทีรหัสของคุณอาจใช้ไม่ได้กับฉันเพราะฉันใช้ >> เพื่อจับ stdout?
Nick

17

ฉันมีชุดของไฟล์ที่ลงท้ายด้วย stats.txt ที่ฉันต้องการเชื่อมต่อกับชื่อไฟล์

ฉันทำสิ่งต่อไปนี้และเมื่อมีมากกว่าหนึ่งไฟล์คำสั่ง "มากกว่า" จะรวมชื่อไฟล์เป็นส่วนหัว

more *stats.txt > stats.txt

หรือสำหรับกรณีทั่วไป

more FILES_TO_CONCAT > OUTPUT_FILE

6
more <FILES> | cat
คิวเมนตัส

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

สิ่งนี้จะพิมพ์ชื่อไฟล์แบบเต็ม (รวมถึงเส้นทาง) จากนั้นเนื้อหาของไฟล์ นอกจากนี้ยังมีความยืดหยุ่นสูงเนื่องจากคุณสามารถใช้ -name "expr" สำหรับคำสั่ง find และรันคำสั่งได้มากเท่าที่คุณต้องการบนไฟล์


1
grepนอกจากนี้ยังค่อนข้างตรงไปตรงมารวมกับ วิธีใช้กับbash:find . -type f -print | grep PATTERN | xargs -n 1 -I {} -i bash -c 'echo ==== {} ====; cat {}; echo'
dojuba

5

นี่คือวิธีที่ฉันจัดการการจัดรูปแบบตามปกติ:

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

ฉันมักจะทำให้แมวกลายเป็น grep สำหรับข้อมูลเฉพาะ


3
ระวังที่นี่ for i in *จะไม่รวมไดเรกทอรีย่อย
คิวเมนตัส

5

ฉันชอบตัวเลือกนี้

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

ผลลัพธ์มีดังนี้:

./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

5

และโซลูชัน awk ที่ขาดหายไปคือ:

$ awk '(FNR==1){print ">> " FILENAME " <<"}1' *

ขอบคุณสำหรับคำตอบที่ดี คุณสามารถอธิบายความหมายของคำ1ว่าท้ายคำได้หรือไม่?
bwangel


3

คุณสามารถใช้คำสั่งง่าย ๆ นี้แทนการใช้ for for loop

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

3

ถ้าคุณชอบสีลองสิ่งนี้:

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

หรือ:

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

หรือ: (ติดตั้งแพ็คเกจ 'multitail')

multitail *

1
เพื่อเน้นสีที่เน้นชื่อไฟล์:find . -type f -name "*.txt" | xargs -I {} bash -c "echo $'\e[33;1m'{}$'\e[0m';cat {}"
MediaVince

3

หากไฟล์ทั้งหมดมีชื่อเดียวกันหรือสามารถจับคู่ได้findคุณสามารถทำได้ (เช่น):

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

เพื่อค้นหาแสดงเส้นทางและ cat แต่ละไฟล์


2

นี่เป็นวิธีที่ง่ายจริงๆ คุณบอกว่าคุณต้องการแมวซึ่งหมายความว่าคุณต้องการดูไฟล์ทั้งหมด แต่คุณต้องพิมพ์ชื่อไฟล์ด้วย

ลองสิ่งนี้

head -n99999999 * หรือ head -n99999999 file1.txt file2.txt file3.txt

หวังว่าจะช่วย


4
head -n -0 file.txt file2.txt file3.txtไวยากรณ์ทำความสะอาดจะเป็น ใช้งานได้headใน GNU coreutils
doubleDown

1

วิธีนี้จะพิมพ์ชื่อไฟล์แล้วเนื้อหาไฟล์:

tail -f file1.txt file2.txt

เอาท์พุท:

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

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

3
สิ่ง-fนี้มีประโยชน์ถ้าคุณต้องการติดตามไฟล์ที่ถูกเขียนไป แต่ไม่ได้อยู่ในขอบเขตของสิ่งที่ OP ถาม
tripleee

1

หากคุณต้องการแทนที่สิ่งที่น่าเกลียดเหล่านั้น ==> <== ด้วยสิ่งอื่น

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

คำอธิบาย:

tail -n +1 *.txt - ส่งออกไฟล์ทั้งหมดในโฟลเดอร์ที่มีส่วนหัว

sed -e 's/==>/\n###/g' -e 's/<==/###/g'- แทนที่==>ด้วยบรรทัดใหม่ + ###และ<==มีเพียง ###

>> "files.txt" - ส่งออกทั้งหมดไปยังไฟล์



0

หากคุณต้องการผลลัพธ์ในรูปแบบเดียวกับผลลัพธ์ที่คุณต้องการคุณสามารถลอง:

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

ผลลัพธ์:

file1
bluemoongoodbeer
file2
awesomepossum
file3
hownowbrowncow

คุณสามารถใส่echo -eก่อนและหลังการตัดเพื่อให้คุณมีระยะห่างระหว่างบรรทัดเช่นกัน:

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

ผลลัพธ์:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow

คำอธิบาย: forวนรอบผ่านรายการlsผลลัพธ์คำสั่ง $ ls file{1..3}.txtผลลัพธ์: file1.txt file2.txt file3.txtแต่ละการวนซ้ำจะechoเป็น$fileสตริงจากนั้นจะถูกส่งไปยังcutคำสั่งที่ฉันใช้.เป็นตัวคั่นฟิลด์ซึ่งแบ่ง fileX.txt ออกเป็นสองส่วนและพิมพ์ฟิลด์ 1 (field2 คือ txt) ส่วนที่เหลือควรชัดเจน
Fekete Sumér

0
  • AIX 7.1 ksh

... glomming ไปยังผู้ที่ได้กล่าวแล้วหัวผลงานบางส่วนของเรา:

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

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

==> file3.txt <==
zzz
$

ความต้องการของฉันคืออ่านบรรทัดแรก ตามที่ระบุไว้ถ้าคุณต้องการมากกว่า 10 บรรทัดคุณจะต้องเพิ่มตัวเลือก (หัว -9999 เป็นต้น)

ขออภัยสำหรับการโพสต์ความคิดเห็นอนุพันธ์; ฉันไม่มีเครดิตถนนเพียงพอที่จะแสดงความคิดเห็น / เพิ่มความคิดเห็นของใครบางคน


-1

สำหรับการแก้ปัญหานี้ฉันมักจะใช้คำสั่งต่อไปนี้:

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

เป็นวิธีที่สะดวกมากในการต่อไฟล์หากจำนวนไฟล์มีขนาดใหญ่มาก


1
แต่นี่ไม่ได้ตอบคำถามของ OP
kvantour

-3

ก่อนอื่นฉันสร้างแต่ละไฟล์: echo 'information'> file1.txt สำหรับแต่ละไฟล์ [123] .txt

จากนั้นฉันพิมพ์แต่ละไฟล์เพื่อให้แน่ใจว่าข้อมูลถูกต้อง: ไฟล์ท้าย?

จากนั้นฉันทำสิ่งนี้: ไฟล์หาง? .txt >> Mainfile.txt สิ่งนี้สร้าง Mainfile.txt เพื่อเก็บข้อมูลในแต่ละไฟล์ลงในไฟล์หลัก

cat Mainfile.txt ยืนยันว่าใช้ได้

==> file1.txt <== bluemoongoodbeer

==> file2.txt <== awesomepossum

==> file3.txt <== hownowbrowncow

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.