วิธีผนวกหนึ่งไฟล์ไปยังอีกไฟล์ใน Linux จาก shell ได้อย่างไร?


418

ฉันมีสองไฟล์: และfile1 file2ฉันจะผนวกเนื้อหาของfile2เพื่อfile1ให้เนื้อหาของfile1กระบวนการยังคงอยู่ได้อย่างไร?

คำตอบ:


611

2
คุณจะทำอย่างไรไฟล์ปลายทางไม่ได้เป็นของคุณและคุณต้องใช้ sudo?
Bijay Rungta

1
@BijayRungta: ดูเหมือนคุณตอบคำถามของคุณเอง คุณต้องการก่อนแขวนsudoกับcatคำสั่ง (และป้อนข้อมูลประจำตัวหากมีการแจ้ง)
เดวิด

คุณจำเป็นต้อง ... chmod 777 / etc / default / docker เพื่อให้สิทธิ์การเขียนในไฟล์นั้น - ให้แน่ใจว่าได้คืนค่าการอนุญาตไฟล์เก่าเมื่อเสร็จแล้ว
danday74

1
@Sigur: หากไม่มีวิธีที่จะส่งเอาต์พุตไปยังสองไฟล์พร้อมกันมันจะเกี่ยวข้องกับการเรียกใช้คำสั่งสองครั้ง
David

2
@Sigur หรือดูที่teeโปรแกรม: cat 1 | tee -a 2 3. คุณสามารถใส่ไฟล์ได้มากเท่าที่คุณต้องการหลังจากสวิตช์--append(หรือ-aสั้น ๆ )
Stefan van den Akker

291

cat file2 >> file1

>>ประกอบการผนวกการส่งออกไปยังไฟล์ชื่อหรือสร้างไฟล์ชื่อถ้ามันไม่ได้อยู่

cat file1 file2 > file3

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

cat *.txt >> newfile.txt

อัปเดต 20130902
ในความคิดเห็น eumiro แนะนำ "อย่าลองcat file1 file2 > file1" เหตุผลที่อาจไม่ส่งผลให้ผลลัพธ์ที่คาดหวังคือไฟล์ที่ได้รับการเปลี่ยนเส้นทางถูกจัดทำขึ้นก่อนที่คำสั่งทางด้านซ้ายของไฟล์>จะถูกดำเนินการ ในกรณีนี้เป็นครั้งแรกที่file1ถูกตัดทอนให้เป็นศูนย์ความยาวและเปิดสำหรับการส่งออกแล้วcatพยายามคำสั่งเพื่อ concatenate ไฟล์ความยาวเป็นศูนย์ตอนนี้บวกกับเนื้อหาของเข้าfile2 file1ผลที่ได้คือเนื้อหาต้นฉบับของfile1สูญหายและในสถานที่คือสำเนาfile2ซึ่งอาจไม่เป็นไปตามที่คาดไว้

ปรับปรุง 20160919
ในความคิดเห็น tpartee แนะนำการเชื่อมโยงไปยังการสำรองข้อมูล / แหล่งที่มา สำหรับการอ้างอิงที่มีสิทธิ์ฉันนำผู้อ่านที่ใจดีไปยังหน้า man shที่ linuxcommand.org ซึ่งระบุว่า:

ก่อนที่จะดำเนินการคำสั่งอินพุตและเอาต์พุตอาจถูกเปลี่ยนทิศทางโดยใช้สัญลักษณ์พิเศษที่ตีความโดยเชลล์

ในขณะที่จะบอกผู้อ่านสิ่งที่พวกเขาจำเป็นต้องรู้มันเป็นเรื่องง่ายที่จะพลาดถ้าคุณไม่ได้มองหามันและแยกคำคำต่อคำ คำที่สำคัญที่สุดที่นี่คือ 'ก่อน' การเปลี่ยนเส้นทางเสร็จสมบูรณ์ (หรือล้มเหลว) ก่อนที่คำสั่งจะถูกดำเนินการ

ในกรณีตัวอย่างของcat file1 file2 > file1เชลล์ทำการเปลี่ยนทิศทางก่อนเพื่อให้มีการจัดการ I / O ในสภาพแวดล้อมที่คำสั่งจะถูกดำเนินการก่อนที่จะถูกดำเนินการ

เวอร์ชันที่เป็นมิตรกว่าที่ความสำคัญในการเปลี่ยนเส้นทางถูกครอบคลุมได้ที่เว็บไซต์ของ Ian Allen ในรูปแบบของบทเรียน Linux หน้าI / O Redirection Notes ของเขามีหลายสิ่งที่จะพูดในหัวข้อรวมถึงการสังเกตว่าการเปลี่ยนเส้นทางทำงานได้แม้ไม่มีคำสั่ง ผ่านสิ่งนี้ไปที่เปลือก:

$ >out

... สร้างไฟล์ว่างที่มีชื่อว่า เชลล์ตั้งค่าการเปลี่ยนเส้นทาง I / O ก่อนจากนั้นค้นหาคำสั่งค้นหาไม่พบและดำเนินการให้เสร็จสิ้น


17
@asir - อย่าลองcat file1 file2 > file1- สิ่งนี้จะไม่ทำงานเหมือนที่คุณกำลังรออยู่
eumiro

5
จริงๆแล้วนี่คือสิ่งที่เขาต้องการ เขาพูดว่า "ไม่เขียนทับไฟล์ปัจจุบัน 1" สาม answerers แรกได้ละเว้นสมบูรณ์ส่วนหนึ่งของคำถามนี้และแนะนำคำสั่งที่ใช้>>ซึ่งจะfile1แก้ไขไฟล์ T.Rob ทำงานที่เหนือกว่าอย่างมากในการอธิบายคำตอบของเขาแทนที่จะแข่งเพื่อส่งบางสิ่งที่เป็นจริงแล้วไม่ถูกต้อง จากข้อความของคำถามฉันเชื่อว่าcat file1 file2 > file3เป็นคำสั่งที่เหมาะสมที่ @asir กำลังมองหา
dm78

ขอบคุณสำหรับคำพูดที่ใจดีเดวิด! สิ่งที่ @eumiro ชี้ให้เห็นข้างต้น แต่ไม่ได้ลงรายละเอียดว่าการดำเนินการทางด้านขวาของ>ถูกดำเนินการก่อน ดังนั้นการเรียกใช้งานcat file1 file2 > file1จะทำให้เกิดการอุดตันก่อนfile1จากนั้นจึงพยายามคัดลอกไฟล์ที่มีความยาวเป็นศูนย์ตอนนี้ไปยังตัวมันเอง สิ่งนี้สมเหตุสมผลเมื่อคุณนึกถึงลำดับที่การดำเนินการอาจเกิดขึ้นและควรเกิดขึ้น แต่มีความละเอียดอ่อนพอที่จะทำให้คนจำนวนมากประหลาดใจ ดังนั้นหากไม่มีสิ่งใด eumiro และคุณได้รับแจ้งให้ปรับปรุงคำตอบต่อไป ขอบคุณสำหรับสิ่งนั้น!
T.Rob

ยังไม่ลอง cat file1 >> file1 นี้จะทำให้ไฟล์ถูกเขียนซ้ำซ้ำฉันทำผิดพลาดและภายในไม่กี่วินาที 50 ล้านบรรทัดถูกใส่เข้าไปในไฟล์จากก่อนหน้านี้เพียงไม่กี่บรรทัด
Hendra Uzia

นอกจากนี้เพื่อให้รัดกุมขึ้นอีกเล็กน้อยหากมี "ไฟล์ใหม่" อยู่แล้วให้>> ผนวกเข้ากับไฟล์และ> แทนที่ไฟล์
rinogo

43

หมายเหตุ : หากคุณต้องการใช้sudoให้ทำสิ่งนี้:

sudo bash -c 'cat file2 >> file1'

วิธีการปกติของsudoการต่อเติมคำสั่งเพียงอย่างเดียวจะล้มเหลวเนื่องจากการเพิ่มสิทธิ์ไม่ได้นำไปสู่การเปลี่ยนเส้นทางเอาต์พุต


6
สำนวนสามัญอื่นสำหรับเรื่องนี้คือcat file2 | sudo tee -a file1 > /dev/null
ianw


13

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

ddrescue -o $(wc --bytes file1 | awk '{ print $1 }') file2 file1 logfile

logfileเป็นบิตที่สำคัญ คุณสามารถขัดจังหวะกระบวนการด้วยCtrl-Cและดำเนินการต่อโดยการระบุคำสั่งเดียวกันที่แน่นอนอีกครั้งและ ddrescue จะอ่านlogfileและดำเนินการต่อจากที่มันค้างไว้ -o Aธงบอก ddrescue เริ่มต้นจากไบต์ในแฟ้มผลลัพธ์ ( ) ดังนั้นเพียงแยกขนาดเป็นไบต์ (คุณสามารถวางผลลัพธ์จากถ้าคุณต้องการ)file1wc --bytes file1 | awk '{ print $1 }'file1ls

ตามที่ระบุโดยngksในความคิดเห็นข้อเสียคือ ddrescue จะไม่ถูกติดตั้งโดยค่าเริ่มต้นดังนั้นคุณจะต้องติดตั้งด้วยตนเอง ภาวะแทรกซ้อนอื่น ๆ คือว่ามีสองรุ่นของ ddrescue ซึ่งอาจอยู่ในที่เก็บของคุณ: ดูคำถาม askubuntu นี้สำหรับข้อมูลเพิ่มเติม รุ่นที่คุณต้องการคือ GNU ddrescue และระบบที่ใช้เดเบียนคือแพ็คเกจที่มีชื่อว่าgddrescue:

sudo apt install gddrescue

สำหรับ distros อื่น ๆ ให้ตรวจสอบระบบการจัดการแพ็คเกจของคุณสำหรับรุ่นGNUของ ddrescue


1
เพื่อประโยชน์ของผู้ใช้ใหม่: ddrescue เป็นเครื่องมือ GNU แต่อาจไม่มีอยู่ใน Linux, Mac หรือระบบที่คล้ายยูนิกซ์อื่น ๆ ddrescue ไม่ปรากฏว่าเป็นที่ต้องการโดย POSIX หรือมาตรฐานอื่น ๆ

2

ทางออกอื่น:

cat file1 | tee -a file2

tee มีประโยชน์ที่คุณสามารถผนวกเข้ากับไฟล์ได้มากเท่าที่คุณต้องการตัวอย่างเช่น

cat file1 | tee -a file2 file3 file3

จะผนวกเนื้อหาของfile1การfile2, และfile3file4

จากหน้าคน:

-a, --append
       append to the given FILEs, do not overwrite

0

catอาจเป็นทางออกที่ง่าย แต่ที่ช้ามากเมื่อเราต่อไฟล์ขนาดใหญ่เข้าด้วยกันfind -printคือช่วยคุณแม้ว่าคุณจะต้องใช้แมวหนึ่งครั้ง

amey@xps ~/work/python/tmp $ ls -lhtr
total 969M
-rw-r--r-- 1 amey amey 485M May 24 23:54 bigFile2.txt
-rw-r--r-- 1 amey amey 485M May 24 23:55 bigFile1.txt

 amey@xps ~/work/python/tmp $ time cat bigFile1.txt bigFile2.txt >> out.txt

real    0m3.084s
user    0m0.012s
sys     0m2.308s


amey@xps ~/work/python/tmp $ time find . -maxdepth 1 -type f -name 'bigFile*' -print0 | xargs -0 cat -- > outFile1

real    0m2.516s
user    0m0.028s
sys     0m2.204s

ประหยัดเวลาที่คุณรายงานสำหรับคำสั่งผสมคำสั่ง find / cat ของคุณเพราะคุณเป็นผู้กำหนดเวลาคำสั่ง find เท่านั้นซึ่งกำลังพิมพ์ชื่อของไฟล์ ลองกำหนดเวลาคำสั่งทั้งหมดเช่นนี้time (find . -maxdepth 1 -type f -name 'bigFile*' -print0 | xargs -0 cat -- > outFile1)และควรให้ผลลัพธ์ที่คล้ายกันกับคำสั่ง cat เท่านั้นของคุณ
JoshMc

0

คุณสามารถทำสิ่งนี้ได้โดยไม่ต้องcatแม้ว่าcatจะอ่านง่ายกว่า:

>> file1 < file2

>>ผนวกSTDINไปfile1และ<ทิ้งfile2ไปSTDIN



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