Bash: คัดลอกไฟล์ที่มีชื่อแบบวนซ้ำรักษาโครงสร้างโฟลเดอร์


103

ฉันหวังว่า:

cp -R src/prog.js images/icon.jpg /tmp/package

จะให้โครงสร้างสมมาตรใน dir ปลายทาง:

/tmp
|
+-- package
    |
    +-- src
    |   |
    |   +-- prog.js
    |
    +-- images
        |
        +-- icon.jpg

แต่ทั้งสองไฟล์จะถูกคัดลอกไปยัง / tmp / package แทน สำเนาแบน (นี่คือบน OSX)

มีฟังก์ชั่นทุบตีง่ายๆที่ฉันสามารถใช้เพื่อคัดลอกไฟล์ทั้งหมดรวมถึงไฟล์ที่ระบุโดยสัญลักษณ์แทน (เช่น src / *. js) ลงในตำแหน่งที่ถูกต้องภายในไดเร็กทอรีปลายทาง คล้ายกับ "สำหรับแต่ละไฟล์ให้เรียกใช้mkdir -p $(dirname "$file"); cp "$file" $(dirname "$file")" แต่อาจเป็นคำสั่งเดียว

นี่เป็นชุดข้อความที่เกี่ยวข้องซึ่งแสดงว่าเป็นไปไม่ได้ วิธีแก้ปัญหาของผู้เขียนไม่มีประโยชน์สำหรับฉันเพราะฉันต้องการเพียงแค่ให้รายการไฟล์สัญลักษณ์แทนหรือไม่และคัดลอกทั้งหมดไปยัง dir ปลายทาง IIRC MS-DOS xcopy ทำสิ่งนี้ แต่ดูเหมือนจะไม่เทียบเท่ากับ cp

คำตอบ:


154

คุณได้ลองใช้ตัวเลือก --parents แล้วหรือยัง? ฉันไม่รู้ว่า OS X รองรับหรือเปล่า แต่ใช้ได้กับ Linux

cp --parents src/prog.js images/icon.jpg /tmp/package

หากไม่ได้ผลบน OS X ให้ลอง

rsync -R src/prog.js images/icon.jpg /tmp/package

ตามที่ aif แนะนำ


4
ขอบคุณ. ปรากฎว่า "cp --parents" ไม่สามารถทำได้บน mac แต่ก็ยินดีที่ได้ทราบธงสำหรับยูนิกซ์อื่น ๆ rsync -R เป็นโซลูชันแบบพกพาที่ง่ายที่สุดสำหรับปัญหานี้
mahemoff

1
ฉันยอมรับอันนี้เพราะความสง่างาม / ความน่าจดจำ แต่เพิ่งค้นพบว่าสิ่งนี้ไม่ได้คัดลอกไดเรกทอรีทั้งหมด (อย่างน้อยบน OSX) ในขณะที่ tar ด้านล่างทำ
mahemoff

cp --parentsเป็นตัวเลือกที่ผิดกฎหมายใน OSX (BSD cp) แต่gcp(GNU cp) ทำงานได้ดี brew install coreutilsถ้ามันไม่ได้อยู่ในระบบของคุณยังใช้ คุณจะมียูทิลิตี้มากมายที่มีคำนำหน้า g
kyb

@mahemoff cp -R --parentsและrsync -rRคัดลอกทั้งไฟล์และไดเร็กทอรีค่อนข้าง
Vortico

22

ทางเดียว:

tar cf - <files> | (cd /dest; tar xf -)

โอ้ฉันชอบคำตอบนี้ดีกว่าคำตอบของฉัน
EMPraptor

4
คุณยังสามารถใช้-Cตัวเลือกเพื่อทำ chdir ให้คุณ - tar cf - _files_ | tar -C /dest xf -หรืออะไรทำนองนั้น
D.Shawley

ขอบคุณนี่เป็นเรื่องที่กระชับแม้ว่าฉันชอบ rsync เพื่อความเรียบง่าย
mahemoff

1
เยี่ยมมาก! มีใครรู้วิธีเปลี่ยนสิ่งนี้ให้เป็นคำสั่งเชลล์หรือไม่? ควรยอมรับอินพุต N N-1 แรกคือไฟล์ที่จะคัดลอกและสุดท้ายคือโฟลเดอร์ปลายทาง
รอด

@arod $ {!} # เป็นพารามิเตอร์ที่ผ่านมาและใช้นี้จะได้รับก่อนการขัดแย้งstackoverflow.com/questions/1215538/... หากคุณเขียนคำสั่งโปรดเชื่อมโยงไปยังส่วนสำคัญที่นี่
mahemoff

18

หรือถ้าคุณเป็นโรงเรียนเก่าให้ใช้ cpio:

cd /source;
find . -print | cpio -pvdmB /target

เห็นได้ชัดว่าคุณสามารถกรองรายการไฟล์ให้ตรงกับเนื้อหาใจของคุณได้

ตัวเลือก '-p' ใช้สำหรับโหมด 'pass-through' (เทียบกับ '-i' สำหรับอินพุตหรือ '-o' สำหรับเอาต์พุต) '-v' คือ verbose (แสดงรายการไฟล์ที่กำลังประมวลผล) '-m' รักษาเวลาการแก้ไข '-B' หมายถึงใช้ 'บล็อกขนาดใหญ่' (โดยที่บล็อกขนาดใหญ่คือ 5120 ไบต์แทนที่จะเป็น 512 ไบต์) เป็นไปได้ว่าวันนี้ไม่มีผล


1
จะดีกว่าที่จะใช้-print0ร่วมกับ--nullตัวเลือกเพื่อที่จะไม่แตกกับอักขระพิเศษและเช่น:find . -print0 | cpio -pvdmB --null /target
haridsv

เรียกมันว่าโรงเรียนเก่าเรียกว่าพกพาเรียกว่าอะไรก็ได้ แต่ฉันเชื่อมั่นcpioในงานนี้แน่นอน ฉันยอมรับว่าควรใช้ตัวเลือก-print0และ-nullตัวเลือกมิฉะนั้นในบางจุดจะมีคนให้ "อักขระพิเศษ" (ช่องว่างเป็นไปได้มากที่สุด) และจะมีบางอย่างเกิดขึ้น ไม่ใช่ว่าฉันพูดจากประสบการณ์ส่วนตัว แต่คุณอาจพยายามสำรองไฟล์จำนวนมากและจบลงด้วยการสำรองข้อมูลเพียงครึ่งเดียวเนื่องจากมีช่องว่างในชื่อไฟล์ (โอเคฉันพูดจากประสบการณ์ส่วนตัว)
bballdave025

@ bballdave025: คุณจะพบปัญหาcpioดังที่แสดงหากชื่อไฟล์มีการขึ้นบรรทัดใหม่ - จากนั้นคุณจะพบข้อความแสดงข้อผิดพลาดเกี่ยวกับชื่อไฟล์สองชื่อ (หรือมากกว่า) ที่ไม่พบสำหรับแต่ละบรรทัดใหม่ในชื่อไฟล์ (บางครั้งคุณอาจได้รับข้อความน้อยลง แต่ต้องใช้ความระมัดระวังเป็นอย่างมากในการสร้างกรณีทดสอบ) เมื่อฉันใช้cpioไม่มี--nullตัวเลือก ตัวเลือก double-dash ไม่ได้เป็นส่วนหนึ่งของสัญกรณ์ตัวเลือก SVR4 และแนวคิดของ-print0ก็ไม่ได้อยู่ในfindรูปแบบ. แต่นั่นเป็นเวลานานมาแล้ว (เช่นกลางทศวรรษที่ 90 ก่อนที่ Linux จะครองอำนาจ)
Jonathan Leffler

ขอบคุณสำหรับรายละเอียด @Jonathan_Leffler ฉันชอบเรียนรู้สิ่งต่างๆที่นี่ ตอนนี้ฉันพยายามจำความผิดพลาด
ซ้ำซากที่

@ bballdave025— ความเป็นไปได้อย่างหนึ่งที่ใช้xargsในการผสมผสาน - มันแบ่งออกเป็นช่องว่าง - ช่องว่างแท็บบรรทัดใหม่ OTOH ฉันไม่แน่ใจว่าคุณทำอย่างนั้นหรืออย่างไร GNU cpiomanul ในโหมดเอาต์พุตมีความชัดเจนเกี่ยวกับชื่อไฟล์หนึ่งชื่อต่อบรรทัด คู่มือผู้ใช้ SVR4 (พิมพ์ปี 1990) เป็น vaguer: cpio -o(โหมดคัดลอกออก) อ่านอินพุตมาตรฐานเพื่อรับรายการชื่อพา ธ และคัดลอกไฟล์เหล่านั้นไปยังเอาต์พุตมาตรฐานพร้อมกับชื่อพา ธ และข้อมูลสถานะ ดังนั้นจึงมีโอกาสที่จะทำลายชื่อในช่องว่าง
Jonathan Leffler

16

ตัวเลือก -R ของ rsyncจะทำในสิ่งที่คุณคาดหวัง มันเป็นเครื่องถ่ายเอกสารไฟล์ที่มีคุณสมบัติมากมาย ตัวอย่างเช่น:

$ rsync -Rv src/prog.js images/icon.jpg /tmp/package/
images/
images/icon.jpg
src/
src/prog.js

sent 197 bytes  received 76 bytes  546.00 bytes/sec
total size is 0  speedup is 0.00

ตัวอย่างผลลัพธ์:

$ find /tmp/package
/tmp/package
/tmp/package/images
/tmp/package/images/icon.jpg
/tmp/package/src
/tmp/package/src/prog.js


1

ลอง...

for f in src/*.js; do cp $f /tmp/package/$f; done

สำหรับสิ่งที่คุณทำในตอนแรก ...

for f in `echo "src/prog.js images/icon.jpg"`; do cp $f /tmp/package/$f; done

หรือ

v="src/prog.js images/icon.jpg"; for f in $v; do cp $f /tmp/package/$f; done

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