การต่อเชื่อมไฟล์ข้อความหลายไฟล์เป็นไฟล์เดียวใน Bash


305

วิธีที่เร็วและจริงจังที่สุดในการรวมไฟล์ * .txt ทั้งหมดในไดเรกทอรีเป็นไฟล์ข้อความขนาดใหญ่หนึ่งไฟล์คืออะไร

ขณะนี้ฉันใช้ windows กับ cygwin ดังนั้นฉันจึงสามารถเข้าถึง BASH ได้

คำสั่งเชลล์ของ Windows จะดีเช่นกัน แต่ฉันสงสัยว่ามันมีอยู่

คำตอบ:


537

ส่วนนี้จะผนวกเอาท์พุทไปที่ all.txt

cat *.txt >> all.txt

นี่เขียนทับ all.txt

cat *.txt > all.txt

30
คุณอาจพบปัญหาที่ cat all.txt เป็น all.txt ... ฉันมีปัญหากับ grep ในบางครั้งไม่แน่ใจว่า cat มีพฤติกรรมแบบเดียวกันหรือไม่
rmeador

8
@rmeador ใช่นั่นเป็นจริงหาก all.txt มีอยู่แล้วคุณจะมีปัญหานี้ ปัญหานี้แก้ไขได้ด้วยการให้ไฟล์เอาต์พุตที่มีนามสกุลต่างกันหรือย้าย all.txt ไปยังโฟลเดอร์อื่น
Robert Greiner

2
cat * .txt >> tmp; mv tmp all.txt (และตรวจสอบให้แน่ใจว่าไม่มี all.txt ไว้ก่อน)
Renaud

16
ฉันได้รับ "รายการอาร์กิวเมนต์ยาวเกินไป" - เดาว่าไม่สามารถจัดการไฟล์ได้มากกว่า 40,000 ไฟล์
Matt

32
หลีกเลี่ยงรายการอาร์กิวเมนต์ที่ยาวเกินไปด้วย:echo *.txt | xargs cat > all.txt
5heikki

145

เพียงจำไว้ว่าสำหรับการแก้ปัญหาทั้งหมดที่ให้มาจนถึงตอนนี้เชลล์จะตัดสินใจลำดับการเรียงไฟล์ สำหรับ Bash, IIRC นั้นเป็นลำดับตัวอักษร หากการสั่งซื้อมีความสำคัญคุณควรตั้งชื่อไฟล์อย่างเหมาะสม (01file.txt, 02file.txt, ฯลฯ ... ) หรือระบุแต่ละไฟล์ตามลำดับที่คุณต้องการให้เรียงกัน

$ cat file1 file2 file3 file4 file5 file6 > out.txt

33

คำสั่งเชลล์ของ Windows typeสามารถทำสิ่งนี้:

type *.txt >outputfile

typeคำสั่งType ยังเขียนชื่อไฟล์ไปยัง stderr ซึ่งไม่ได้ถูกจับโดย>โอเปอเรเตอร์การเปลี่ยนเส้นทาง (แต่จะแสดงบนคอนโซล)


2
โปรดทราบว่าหากคุณวางไฟล์เอาต์พุตในไดเรกทอรีเดียวกันกับไฟล์ต้นฉบับมันจะทำให้เกิดการซ้ำซ้อนเพราะมันจะรวมไฟล์เอาต์พุตใหม่สองครั้งด้วย
CathalMF

26

คุณสามารถใช้เชลล์ Windows copyเพื่อต่อไฟล์เข้าด้วยกัน

C:\> copy *.txt outputfile

จากความช่วยเหลือ:

ในการผนวกไฟล์ให้ระบุไฟล์เดียวสำหรับปลายทาง แต่มีหลายไฟล์สำหรับแหล่งที่มา (โดยใช้สัญลักษณ์แทนหรือรูปแบบ file1 + file2 + file3)


นี่เป็นคำตอบที่สะอาดที่สุดของ IMHO โดยไม่มีผลข้างเคียงใด ๆ ที่ผู้เริ่มต้นสามารถเดินทางข้ามได้ แต่น่าเสียดายที่ไม่ได้รับการชื่นชมมากพอ :-(
Grmpfhmbl

OP ขอ Bash
Big Rich

2
คุณอ่านคำถามหรือไม่ "คำสั่งเชลล์ของ Windows จะดีเช่นกัน ... "
Carl Norum

8

โปรดระวังเนื่องจากวิธีการเหล่านี้ไม่สามารถทำงานกับไฟล์จำนวนมากได้ ส่วนตัวผมใช้สายนี้:

for i in $(ls | grep ".txt");do cat $i >> output.txt;done

แก้ไข: ตามที่มีคนพูดในความคิดเห็นคุณสามารถแทนที่$(ls | grep ".txt")ด้วย$(ls *.txt)

แก้ไข: ขอบคุณ @gnourf_gnourf ความเชี่ยวชาญการใช้globเป็นวิธีที่ถูกต้องในการวนซ้ำไฟล์ในไดเรกทอรี ดังนั้น$(ls | grep ".txt")ต้องเปลี่ยนนิพจน์ดูหมิ่นเช่นนี้*.txt(ดูบทความที่นี่ )

ทางออกที่ดี

for i in *.txt;do cat $i >> output.txt;done

1
ทำไมfor i in $(ls *.txt);do cat $i >> output.txt;doneล่ะ
streamofstars

2
บังคับParsingLsเชื่อมโยงร่วมกับ downvote (และคุณสมควรได้รับมากกว่าหนึ่ง downvote เพราะls | grepเป็น antipattern ไม่ดีอย่างจริงจัง)
gniourf_gniourf

รับ upvote จากฉันเพราะมันช่วยให้การทดสอบ / การดำเนินงานโดยพลการโดยชื่อไฟล์ก่อนที่จะส่งออกและมันเป็นเรื่องง่ายและรวดเร็วและดีสำหรับการปฏิบัติ (ในกรณีของฉันฉันต้องการ: สำหรับฉันใน *; ทำ echo -e "\ n $ i: \ n"; cat $ 1; เสร็จแล้ว)
Nathan Chappell

จะไม่ls *.txtล้มเหลวหรือไม่หากมีไฟล์มากเกินไป (ข้อผิดพลาดในรายการอาร์กิวเมนต์ยาวเกินไป)?
Rafael Almeida

6

วิธีปฏิบัติมากที่สุดกับเชลล์คือคำสั่ง cat วิธีอื่น ๆ ได้แก่

awk '1' *.txt > all.txt
perl -ne 'print;' *.txt > all.txt

1
นี่ควรเป็นคำตอบที่ถูกต้องสำหรับสถานการณ์ส่วนใหญ่ หากไฟล์ข้อความใด ๆ ที่ไม่มีบรรทัดใหม่ว่างการใช้catวิธีการด้านบนทั้งหมดจะต่อกันบรรทัดสุดท้ายและบรรทัดแรกจากไฟล์ที่อยู่ติดกัน
mootmoot

6

วิธีการเกี่ยวกับวิธีนี้

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

ตั้งแต่ OP กล่าวว่าไฟล์ที่อยู่ในไดเรกทอรีเดียวกันคุณอาจต้องเพิ่ม-maxdepth 1ไปยังfindคำสั่ง
codeforester

1
ใช้งานได้ดีกับไฟล์จำนวนมากซึ่งวิธีการตอบกลับที่ยอมรับนั้นล้มเหลว
amine

อ่าฉันหวังว่าฉันจะรู้ว่าสิ่งนี้บวกและการเปลี่ยนเส้นทางสองครั้งมีความหมาย ...
hello_earth

นี่ควรเป็นคำตอบที่ถูกต้อง มันจะทำงานอย่างถูกต้องในเชลล์สคริปต์ นี่เป็นวิธีการที่คล้ายกันหากคุณต้องการเรียงลำดับผลลัพธ์:sort -u --output="$OUTPUT_FILE" --files0-from=- < <(find "$DIRECTORY_NAME" -maxdepth 1 -type f -name '*.txt' -print0)
steveH

3
type [source folder]\*.[File extension] > [destination folder]\[file name].[File extension]

ตัวอย่างเช่น:

type C:\*.txt > C:\1\all.txt

ที่จะนำไฟล์ txt ทั้งหมดใน C: \ Folder และบันทึกใน C: \ 1 โฟลเดอร์ด้วยชื่อของ all.txt

หรือ

type [source folder]\* > [destination folder]\[file name].[File extension]

ตัวอย่างเช่น:

type C:\* > C:\1\all.txt

ที่จะนำไฟล์ทั้งหมดที่มีอยู่ในโฟลเดอร์และใส่เนื้อหาใน C: \ 1 \ all.txt


0

คุณสามารถทำสิ่งนี้: cat [directory_path]/**/*.[h,m] > test.txt

หากคุณใช้{}เพื่อรวมส่วนขยายของไฟล์ที่คุณต้องการค้นหาแสดงว่ามีปัญหาการเรียงลำดับ


0

เมื่อคุณพบปัญหาที่จะทำให้ all.txt เป็น all.txt คุณสามารถลองตรวจสอบว่า all.txt มีอยู่หรือไม่ถ้ามีอยู่ให้ลบ

แบบนี้:

[ -e $"all.txt" ] && rm $"all.txt"


cat *.txt > all.txt >เขียนทับคำสั่ง all.txt ถ้ามี>>เพิ่มข้อมูลไปยังไฟล์ที่มีอยู่
Oleg Bondarenko

-4

ทั้งหมดนั้นน่ารังเกียจ ....

ls | grep *.txt | while read file; do cat $file >> ./output.txt; done;

สิ่งที่ง่าย


6
Eeek! อย่าทำอย่างนั้น ทำfind . -iname "*.txt" -maxdepth 1 -exec cat {} >> out.txt \;
Chinmay Kanchi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.