วิธีการรวมไฟล์ (ข้อความ) ทั้งหมดในไดเรกทอรีเป็นหนึ่งเดียว?


89

ฉันมี 14 ไฟล์ทั้งหมดเป็นส่วนหนึ่งของข้อความ ฉันต้องการรวมพวกเขาเป็นหนึ่งเดียว ทำอย่างไร

คำตอบ:


168

นี่คือเทคนิคที่catควรทำ ("concatenate") แม้ว่าคนส่วนใหญ่จะใช้เพื่อส่งไฟล์ไปยัง stdout หากคุณให้ชื่อไฟล์หลาย ๆ ไฟล์ชื่อนั้นจะส่งออกไปตามลำดับทั้งหมดจากนั้นคุณสามารถเปลี่ยนเส้นทางนั้นให้เป็นไฟล์ใหม่ ในกรณีของไฟล์ทั้งหมดที่ใช้*(หรือ/path/to/directory/*ถ้าคุณไม่ได้อยู่ในไดเรกทอรีแล้ว) และเชลล์ของคุณจะขยายไปยังชื่อไฟล์ทั้งหมด

$ cat * > merged-file

15
ระวังว่าคำสั่งที่ยกมาของคุณอาจทำในสิ่งที่ผู้โพสต์ต้องการหากพวกเขามีหมายเลขในลักษณะที่เชลล์ขยาย*ในลำดับ "ธรรมชาติ" หากคุณมี "file1.txt ... file9.txt ... file14.txt" จะไม่ทำงานเพราะ file1? .txt จะเรียงลำดับระหว่าง file1.txt และ file2.txt คุณต้องเปลี่ยนชื่อเป็น "file01.txt ... file09.txt ... file14.txt" พูดecho *ถ้าคุณไม่แน่ใจ
Warren Young

2
@Warren: จุดดี (หรือคุณสามารถใช้ zsh และตั้งค่าnumeric_glob_sortตัวเลือก)
Gilles

2
@ warren-young ความคิดเห็นคำเตือนที่ถูกต้องมีประโยชน์ แต่ในกรณีที่เกิดขึ้นจริงของฉันคำสั่งไม่สร้างความแตกต่าง (เนื่องจากไฟล์มีคำสั่ง SQL แบบง่าย ๆ เพียงแค่แทรกระเบียนข้อมูลที่ไม่มีการขึ้นต่อกัน)
Ivan

2
ระวังหากจำนวนไฟล์เกินขีด จำกัด คุณสามารถเรียกใช้ในข้อผิดพลาดเช่น - / bin / cat: รายการอาร์กิวเมนต์ยาวเกินไป
Nupur

1
@ ARA1307 ต่อเมื่อมีไฟล์อยู่แล้ว ไม่เช่นนั้น glob จะถูกขยายก่อนที่เชลล์จะเปิดไฟล์เพื่อเขียนลงไป จุดดีในสถานการณ์นั้น
Michael Mrozek

25

หากไฟล์ของคุณไม่อยู่ในไดเรกทอรีเดียวกันคุณสามารถใช้คำสั่ง find ก่อนการต่อข้อมูล:

find /path/to/directory/ -name *.csv -print0 | xargs -0 -I file cat file > merged.file

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


พกพาได้มากกว่า:

find /path/to/directory/ -name *.csv -exec cat {} + > merged.file

สิ่งนี้อาจเป็นไปได้หรือไม่รักษาลำดับไฟล์


1
นี่คือวิธีที่จะไปหากคุณมีไฟล์จำนวนมาก คุณหลีกเลี่ยงข้อผิดพลาด "รายการอาร์กิวเมนต์ยาวเกินไป"
МатиТернер

2
คุณต้องการ -name "* .csv" แทน -name * .csv - โดยไม่ต้องใส่เครื่องหมายอัญประกาศ
Peteris

ความต้องการอัญประกาศขึ้นอยู่กับเวอร์ชันของคำสั่ง find โดยเฉพาะอย่างยิ่งใน find และ awk มันเป็นปัญหาเมื่อคุณอยู่บน mac เวอร์ชั่นของทั้งสองโปรแกรมนั้นเก่าไปหน่อย จนถึงตอนนี้บน Ubuntu, fedora, debian และ CentOS มันทำงานได้อย่างราบรื่นโดยไม่มีการเสนอราคา
3nrique0

ผมจะคาดหวังรุ่น unquoted จะทำงานเมื่อมีไม่มีไฟล์ในไดเรกทอรีปัจจุบันตรงกับรูปแบบ"*.csv"ตั้งแต่เปลือกจากนั้นก็จะผ่านตัวอักษรเพื่อ* find
RJHunter


9

คำสั่ง

$ cat * > merged-file

ที่จริงแล้วมีผลข้างเคียงที่ไม่พึงประสงค์ของการรวม 'ไฟล์ผสาน' ในการเรียงต่อกันสร้างไฟล์วิ่งหนี เมื่อต้องการปัดเศษนี้ให้เขียนไฟล์ที่ถูกผสานไปยังไดเรกทอรีอื่น

$ cat * > ../merged-file

หรือใช้การจับคู่รูปแบบที่จะละเว้นไฟล์ที่ผสาน

$ cat *.txt > merged-file

14
cat * > merged-fileทำงานได้ดี Globs ถูกประมวลผลก่อนที่จะสร้างไฟล์ หากmerged-fileมีอยู่แล้วcat(อย่างน้อยของฉัน) จะตรวจพบว่าเป็นไฟล์เอาต์พุตและปฏิเสธที่จะอ่าน หากไฟล์มีอยู่แล้วและคุณมีการเปลี่ยนเส้นทางในภายหลังในไปป์ไลน์แล้วเห็นได้ชัดว่าไม่สามารถทำได้ดังนั้นจากนั้นคุณจะได้รับไฟล์ควบคุมไม่ได้
เควิน

catไม่มีวิธีตรวจสอบว่าไฟล์เป็นไฟล์เอาท์พุตหรือไม่ การเปลี่ยนเส้นทางเกิดขึ้นในเชลล์ catพิมพ์บน stdout เท่านั้น
bfontaine

8

เหมือนที่คนอื่น ๆ พูดที่นี่ ... คุณสามารถใช้ cat

ให้บอกว่าคุณมี:

~/file01
~/file02
~/file03
~/file04
~/fileA
~/fileB
~/fileC
~/fileD

และคุณต้องการเพียงfile01ไปfile03และfileAเพื่อfileC:

cat ~/file01 ~/file02 ~/file03 ~/fileA ~/fileB ~/fileC > merged-file

หรือใช้การขยายรั้ง:

cat ~/file0{1..3} ~/file{A..C} > merged-file

หรือใช้การขยายรั้งนักเล่น:

cat ~/file{0{1..3},{A..C}} > merged-file

หรือคุณสามารถใช้forวง:

for i in file0{1..3} file{A..C}; do cat ~/"$i"; done > merged-file

1
โปรดทราบว่าสตริง[01-03]จะไม่ทำงานเป็นรูปแบบที่ทำให้เป็นก้อนกลม
Kusalananda

0

คุณสามารถระบุpatternไฟล์จากนั้นรวมไฟล์ทั้งหมดดังต่อไปนี้:

cat *pattern* >> mergedfile

0

อีกตัวเลือกหนึ่งคือ:

sed r 1.txt 2.txt 3.txt > merge.txt 

หรือ...

sed h 1.txt 2.txt 3.txt > merge.txt 

หรือ...

sed -n p 1.txt 2.txt 3.txt > merge.txt # -n is mandatory here

หรือไม่มีการเปลี่ยนเส้นทาง ...

 sed wmerge.txt 1.txt 2.txt 3.txt

โปรดทราบว่าการเขียนบรรทัดสุดท้ายยัง merge.txt (ไม่ใช่ wmerge.txt!) คุณสามารถใช้ w "merge.txt" เพื่อหลีกเลี่ยงความสับสนกับชื่อไฟล์และ -n สำหรับเอาต์พุตเงียบ

แน่นอนคุณยังสามารถย่อรายการไฟล์ด้วยไวด์การ์ด ตัวอย่างเช่นในกรณีของไฟล์ที่มีหมายเลขตามตัวอย่างข้างต้นคุณสามารถระบุช่วงด้วยเครื่องหมายปีกกาด้วยวิธีนี้:

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