วิธีคัดลอกโฟลเดอร์แบบวนซ้ำโดยใช้ cemp ได้อย่างไร?


46

เมื่อฉันใช้

cp -R inputFolder outputFolder

ผลลัพธ์ขึ้นอยู่กับบริบท :

  1. ถ้าไม่อยู่ก็จะถูกสร้างขึ้นและเส้นทางโฟลเดอร์โคลนจะเป็นoutputFolderoutputFolder
  2. หากoutputFolderมีอยู่โคลนจะถูกสร้างขึ้นoutputFolder/inputFolder

นี้เป็นที่น่ากลัวเพราะผมต้องการที่จะสร้างสคริปต์การติดตั้งบางส่วนและหากผู้ใช้วิ่งมันสองครั้งโดยไม่ได้ตั้งใจเขาจะได้สร้างขึ้นเป็นครั้งแรกแล้วในการทำงานที่สองทุกสิ่งที่จะถูกสร้างขึ้นอีกครั้งในoutputFolderoutputFolder/inputFolder

  • ฉันต้องการพฤติกรรมแรกเสมอ: สร้างโคลนถัดจากต้นฉบับ (เป็นพี่น้อง)
  • ฉันต้องการใช้cpแบบพกพา (เช่น MINGW ไม่มีการrsyncจัดส่ง)
  • ฉันตรวจสอบcp -R --parentsแต่สิ่งนี้จะสร้างเส้นทางใหม่ตลอดเส้นทางไดเรกทอรีต้นไม้ (ดังนั้นโคลนจะไม่เป็นoutputFolderแต่some/path/outputFolder)
  • --remove-destinationหรือ--updateในกรณีที่ 2 ไม่เปลี่ยนแปลงสิ่งใดสิ่งต่าง ๆ ก็ยังคงถูกคัดลอกไปoutputFolder/inputFolder

มีวิธีการทำเช่นนี้โดยไม่ตรวจสอบการมีอยู่ของoutputFolder(หากโฟลเดอร์ไม่มีอยู่แล้ว ... ) หรือใช้งานrm -rf outputFolderหรือไม่?

วิธีการทำ UNIX แบบพกพาที่ตกลงกันคืออะไร



2
ตัวเลือกเหล่านี้บางตัวไม่ใช่ POSIX ดังนั้นตัวเลือกที่คุณพยายามไม่สามารถพกพาได้ หากคุณสามารถมีชีวิตอยู่กับการขาดความสะดวกในการพกพาทำไมไม่ลองใช้rsyncล่ะ?
muru

1
หากคุณไม่ต้องการใช้การcpไพพ์ระหว่างสองtarคำสั่งเป็นวิธีที่น่าเชื่อถือในการคัดลอกทรี
..

@R .. คุณสามารถให้ตัวอย่างได้หรือไม่ @muru ฉันต้องการให้ทำงานใน MINGW ซึ่งไม่มีการrsyncจัดส่ง
jakub.g

ด้วย tar ของ GNU tar -C input -cf - . | tar -C output -xf -ทำงานได้ -Cเปลี่ยนไดเร็กตอรี่ที่ใช้งานได้, แต่มันไม่ใช่ตัวเลือกมาตรฐาน, ดังนั้นหากมันไม่รองรับคุณต้องรันสอง tars ในได( cd input && tar -cf - . ) | ( cd output && tar -xf - )เร็กตอรี่ที่ใช้งานได้เริ่มต้นเช่น, อย่างไรก็ตามถ้าคุณจัดการกับวินโดวส์
..

คำตอบ:


54

ใช้สิ่งนี้แทน:

cp -R inputFolder/. outputFolder

วิธีนี้ใช้งานได้ในลักษณะเดียวกับที่ว่าใช้cp -R aaa/bbb cccงานหากcccไม่มีอยู่มันจะถูกสร้างเป็นสำเนาbbbและเนื้อหา แต่ถ้าcccมีอยู่แล้วccc/bbbจะถูกสร้างขึ้นเป็นสำเนาbbbและเนื้อหา

เกือบทุกครั้งที่bbbสิ่งนี้ให้พฤติกรรมที่ไม่พึงประสงค์ที่คุณบันทึกไว้ในคำถามของคุณ อย่างไรก็ตามในสถานการณ์ที่เฉพาะเจาะจงนี้bbbเป็นเพียง.ดังนั้นaaa/bbbเป็นจริงaaa/.ซึ่งในทางกลับกันเป็นเพียงaaaแต่โดยชื่ออื่น ดังนั้นเราจึงมีสองสถานการณ์นี้:

  1. ccc ไม่ได้อยู่:

    คำสั่งcp -R aaa/. cccหมายถึง "การสร้างcccและคัดลอกเนื้อหาของaaa/.เข้าccc/.เช่นคัดลอกลงในaaaccc

  2. ccc ไม่มีอยู่:

    คำสั่งcp -R aaa/. cccหมายถึง "คัดลอกเนื้อหาของaaa/.เข้าccc/.เช่นคัดลอกลงในaaaccc


3
นั่นเป็นสิ่งใหม่สำหรับฉัน แต่ดูเหมือนจะใช้งานได้! มันบันทึกไว้ที่ไหน?
Ilmari Karonen

1
ฉันได้ทดสอบinputFolder/.แทนinputFolderและมันใช้งานได้จริงสำหรับ Windows / Git Bash (มันไม่ทำงาน แต่มีเพียงแค่การต่อท้าย/ฉันยังต้องการจุดหลังเครื่องหมายทับ) ฉันให้ +1 เนื่องจากมันน่าสนใจถึงแม้ว่ามันอาจจะยุ่งยากเกินกว่าที่จะใช้ในรหัสสาธารณะ :)
jakub.g

@IlmariJaronen ไม่จำเป็นต้องมีเอกสารอย่างชัดเจน ทำตามคำอธิบายแล้วคุณจะเห็นว่า "ตามกฎ" ง่ายเพียงใด
roaima

18

อย่าคัดลอกโฟลเดอร์คัดลอกเนื้อหาเท่านั้น:

## Create the target directory. The -p suppresses error messages
## if the directory already exists
mkdir -p outputFolder

## Copy the contents recursively, this will not recreate the parent
cp -R inputfolder/* outputfolder/

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

.คริสลงมากอย่างถูกต้องชี้ให้เห็นว่าในทุบตีนี้จะข้ามไฟล์ที่มีชื่อขึ้นต้นด้วย เพื่อหลีกเลี่ยงปัญหานี้คุณสามารถเรียกใช้shopt -s dotglobก่อนเรียกใช้คำสั่งด้านบน

ทั้ง-pสำหรับmkdirและ-Rสำหรับcpจะถูกกำหนดโดย POSIX ดังนั้นนี้ควรจะพกพาอย่างสมบูรณ์แบบ


6
หมายเหตุ: .นี้จะไม่คัดลอกไฟล์ที่เริ่มต้นด้วย ในทุบตีคุณสามารถใช้dotglobสำหรับการที่
Chris Down

2
หมายเหตุวิธีนี้มีแนวโน้มที่จะล้มเหลวหากจำนวนรายการไดเรกทอรีใน inputfolder มีขนาดใหญ่เนื่องจากการขยายตัวของ glob อาจเกินความยาวบรรทัดคำสั่งสูงสุด
Tim Cutts

11

ลองเลือกที่จะ-T cpสิ่งนี้มีอยู่ใน GNU coreutils cpเวอร์ชัน 8.22; มันอาจไม่สามารถพกพาออกไปข้างนอกได้


1
ใช่ดูเหมือนว่านี่เป็นสิ่งที่ฉันต้องการ: cp -T( cp --no-target-directory) unix.stackexchange.com/questions/94831/… น่าเสียดายที่เวอร์ชันของฉันcpเก่ากว่ามาก
jakub.g

1
+1 ใช้นี่แค่วันนี้ -uเป็นตัวเลือกที่ยอดเยี่ยมในการเพิ่มเพื่อให้ขี้เกียจ
PSkocik

4

คุณสามารถใช้rsync:

rsync -uav inputFolder/ outputFolder/

(สังเกตเครื่องหมายทับโดยเฉพาะหลังจากอันแรก)


0

ในความคิดของฉันไม่มีอะไรที่ง่ายและพกพาง่ายไปกว่าrm -rf outputFolderนี้อีกแล้ว ดังนั้นฉันมักจะยึดติดกับที่ ฉันเข้าใจว่าคำถามของคุณแตกต่าง แต่ฉันคิดว่านี่เป็นวิธีปฏิบัติที่ดีที่สุด


ไม่สำเร็จหากมีการอนุญาตหรือการเป็นเจ้าของเฉพาะในเป้าหมายที่จำเป็นต้องเก็บไว้ หรือถ้ามันเป็น symlink
roaima

1
คำถามต้องการให้ผลลัพธ์cpเป็นเหมือนกันทั้งในกรณีที่ไม่มีไดเรกทอรีและเมื่อมีอยู่ แล้วคุณกำลังพูดเรื่องอะไร
dashohoxha

cpคำสั่งที่กำหนดโดย OP ไม่ได้ให้สิทธิ์ (หรือ timestamps)
roaima

0

คุณสามารถใช้-tตัวเลือกของcpคำสั่งเป็น:

cp -R inputFolder -t outputFolder

ตอนนี้ถ้าไม่มีโฟลเดอร์เป้าหมายมันจะส่งข้อผิดพลาด:

cp: failed to access ‘outputFolder’: No such file or directory

คำสั่ง note ด้านบนจะคัดลอกinputFolderพร้อมกับเนื้อหา (ไม่ใช่เฉพาะเนื้อหาภายใน)

หากคุณต้องการคัดลอกเพียงเนื้อหาของinputFolderมันจะได้รับบิตหากิน (เนื่องจากคุณต้องระมัดระวังในขณะที่ใช้เปลือกกลมขณะใช้เครื่องหมายดอกจัน *)

cp -R  -t outputFolder/ -- inputFolder/*

ตอนนี้ถ้าไม่มีโฟลเดอร์เป้าหมายมันจะส่งข้อผิดพลาด:

cp: failed to access ‘outputFolder’: No such file or directory

ทำงานร่วมกับ cp (GNU coreutils) 8.23

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