วิธีคัดลอกไฟล์ไปยังหลายไดเรกทอรีโดยใช้คำสั่ง gnu cp


210

เป็นไปได้หรือไม่ที่จะคัดลอกไฟล์เดียวไปยังหลายไดเรกทอรีโดยใช้คำสั่ง cp?

ฉันลองสิ่งต่อไปนี้ซึ่งใช้งานไม่ได้:

cp file1 /foo/ /bar/
cp file1 {/foo/,/bar}

ฉันรู้ว่ามันเป็นไปได้โดยใช้ for loop หรือ find แต่มันเป็นไปได้โดยใช้คำสั่ง gnu cp?

คำตอบ:


106

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


ขอบคุณสำหรับคำตอบ! ตอนนี้ฉันคิดเกี่ยวกับมันอีกเล็กน้อยโดยไม่มีธงพิเศษ (ซึ่งไม่มีอยู่) cp จะไม่ทราบว่าแหล่งที่มาคืออะไรและ DIR dir คืออะไร
Tom Feiner

10
นี่ไม่ใช่คำตอบที่ถูกต้อง โปรดดูคำตอบของ Robert Gamble
PlagueHammer

23
@ Nocturne: ส่วนไหนของสิ่งที่ฉันพูดไม่ถูกต้อง? Robert ให้ตัวอย่างการใช้เครื่องมืออื่นเพื่อเรียกใช้ cp หลายครั้งตามที่ฉันแนะนำ มีวิธีแก้ไขที่เป็นไปได้มากมายที่เกี่ยวข้องกับการใช้เครื่องมือหรือสิ่งก่อสร้างอื่น ๆ แต่ OP ได้ระบุว่าเขาทราบแล้วว่าเป็นไปได้
moonshadow

2
น่าเสียดายที่มันจะดีสำหรับ cp (และ scp) เพื่อรองรับคุณสมบัตินั้น แต่เราสามารถใช้ทีออฟเพื่อแยก superuser.com/questions/32630/…
Simon

4
@moonshadow: แน่นอนคำตอบของคุณถูกต้อง ฉันคิดว่า PlagueHammer ต้องการพูดว่าในบริบทนี้คำตอบอื่น ๆ มีประโยชน์มากกว่า บางทีคุณอาจใส่คำตอบลงไปในนั้นด้วย?
สงบสุข

585

คุณไม่สามารถทำสิ่งนี้ได้ด้วยตัวcpเอง แต่คุณสามารถรวมcpกับxargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

จะคัดลอกfile1ไปdir1, และ dir2 จะโทรถึง3 ครั้งเพื่อดูรายละเอียดdir3xargscpxargs


3
ข้อมูลเพิ่มเติมเกี่ยวกับ xargs: cyberciti.biz/faq/…
Chris Bier

24
@Simon ว่างั้นเหรอ? "คุณไม่สามารถทำสิ่งนี้ด้วยตนเองcpเพียงอย่างเดียว" เพราะคำตอบที่พยายามจะเป็นประโยชน์โดยการแนะนำวิธีอื่นไม่ได้หมายความว่าไม่ได้ตอบคำถาม
นิโคล

3
@NickC ผู้ถามระบุ: "ฉันรู้ว่ามันเป็นไปได้โดยใช้ลูป for หรือ find แต่เป็นไปได้หรือไม่ที่ใช้คำสั่ง gnu cp?" คำตอบที่ดีคือคำตอบที่ได้รับการยอมรับ
Simon

25
การกำหนดว่าคำตอบจะได้รับการยอมรับโดยขึ้นอยู่กับว่าพวกเขาตอบคำถามทางเทคนิคหรือไม่และไม่เป็นประโยชน์จริง ๆ
แบคแกมมอน

4
มีประโยชน์มาก! สำหรับผู้เริ่มต้นคนอื่น ๆ เช่นฉัน: คุณไม่สามารถใช้ regex กับ cp ได้ แต่คุณสามารถทำได้ในส่วนแรกของคำสั่งนี้ (เช่นecho dir[1-3] | xargs -n 1 cp filename)
Jason

77

สัญลักษณ์แทนยังทำงานกับรหัส Roberts

echo ./fs*/* | xargs -n 1 cp test 

และความคิดเห็นทั้งหมด ... ตัวอย่างเช่นเมื่อต้องการย้ายไฟล์ที่เป็นเจ้าของรูท (เป็น symlink จริง ๆ ) ที่อยู่บนเดสก์ท็อปของฉันไปยังผู้ใช้เดสก์ท็อปทั้งหมดก่อนอื่นฉันต้อง sudo su (ใช้งานไม่ได้) / * / Desktop / | xargs -n 1 cp -av / home / myusername / Desktop / ไฟล์
David G

19

เท่าที่ฉันเห็นคุณสามารถใช้สิ่งต่อไปนี้:

ls | xargs -n 1 cp -i file.dat

-iตัวเลือกในการหมายถึงคำสั่งที่คุณจะถูกถามว่าจะเขียนทับแฟ้มในไดเรกทอรีปัจจุบันด้วยcp file.datแม้ว่ามันจะไม่ใช่ทางออกอัตโนมัติอย่างสมบูรณ์ แต่ก็ใช้ได้ผลสำหรับฉัน


1
ในขณะที่เป็นการดีที่ได้เพิ่มการ-iป้องกันไว้คุณจะไม่ถามคุณเกี่ยวกับการเขียนทุกไฟล์ใช่ไหม แทนที่จะคัดลอกไปยังไดเรกทอรีหรือไม่
เม่น

1
@Hedgehog ดีฉันคิดว่าคำสั่งนี้มีประโยชน์เมื่อมีไฟล์ในไดเรกทอรีและหนึ่งต้องการคัดลอกไปยังไดเรกทอรีย่อยของไดเรกทอรี ในกรณีนี้ไฟล์สามารถเขียนทับได้เพียงครั้งเดียว ขอบคุณสำหรับคำถามของคุณ!
Evgeny

2
สำหรับฉันมันพิมพ์cp: overwriteคำถามหลายข้อ แต่ฉันไม่ต้องตอบคำถามใด ๆ และไม่ได้เขียนทับไฟล์
Evgeni Sergeev

พิมพ์ชุดคำถาม + คัดลอกไปยังไฟล์ที่มีชื่อ dir ด้วยตัวอักษร ':' ในตอนท้ายไม่มีวิธีแก้ปัญหาการทำงานเลยโซลูชันของ Paul ทำงานได้อย่างสมบูรณ์แบบ
jgpATs2w

19

ผมจะใช้catและteeขึ้นอยู่กับคำตอบที่ผมเห็นที่/superuser/32630/parallel-file-copy-from-single-source-to-multiple-targetscpแทน

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

cat inputfile | tee outfile1 outfile2 > /dev/null

1
การทดสอบคร่าวๆที่ฉันเพิ่งวิ่งแสดงให้เห็นว่านี่เป็นนักแสดงที่ดีที่สุดหากปลายทางของคุณเป็นไดรฟ์ทางกายภาพที่แตกต่างกัน
อยากรู้อยากเห็น

1
หากคุณใช้ bash 3.0 หรือสูงกว่าคุณสามารถใช้ช่วงดังนี้:cat <inputfile> | tee /path-to-files/outfile{1..4} > /dev/null
Samuel

tee < inputfile outfile1 outfile2 > /dev/nullเป็นรูปแบบที่มีประโยชน์ตามคำตอบของ Taywee สังเกตการใช้การเปลี่ยนเส้นทาง io ด้วย '<' เพื่อไม่จำเป็นต้องใช้ piping จาก cat
Alex Telon

10

คำตอบเหล่านี้ดูเหมือนจะซับซ้อนกว่าชัดเจน:

for i in /foo /bar; do cp "$file1" "$i"; done

สง่างามและทำงานได้ทำไดเรกทอรีทั้งหมดใน dir ปัจจุบันหนึ่งสามารถใช้for d in */ ; do cp $file "$i" done
FantomX1

9

ls -db di*/subdir | xargs -n 1 cp File

-bในกรณีที่มีช่องว่างในชื่อไดเรกทอรีมิฉะนั้นมันจะแตกเป็นรายการอื่นโดย xargs มีปัญหากับรุ่น echo นี้


6

ไม่ได้ใช้ cp ต่อ se แต่ ...

สิ่งนี้เกิดขึ้นกับฉันในบริบทของการคัดลอกวิดีโอ Gopro จำนวนมากออกจากการ์ด SD (ช้า) ไปยังไดรฟ์ USB สาม (ช้า) ฉันต้องการอ่านข้อมูลเพียงครั้งเดียวเพราะใช้เวลาตลอดไป และฉันต้องการมันซ้ำ

$ tar cf - src | tee >( cd dest1 ; tar xf - ) >( cd dest2 ; tar xf - ) | ( cd dest3 ; tar xf - )

(และคุณสามารถเพิ่มได้มากขึ้นในส่วน> () ส่วนหากคุณต้องการผลลัพธ์เพิ่มเติม)

ฉันไม่ได้ทำการเปรียบเทียบ แต่มันเร็วกว่า cp-in-a-loop (หรือการเรียกใช้ cp แบบขนาน)


5

หากต้องการใช้การคัดลอกxargsไปยังไดเรกทอรีที่ใช้ไวด์การ์ดบน Mac OS โซลูชันเดียวที่ทำงานกับฉันด้วยช่องว่างในชื่อไดเรกทอรีคือ:

find ./fs*/* -type d -print0 | xargs -0 -n 1 cp test 

ที่ไหนtestคือแฟ้มที่จะคัดลอก
และ./fs*/*ไดเรกทอรีที่จะคัดลอกไป

ปัญหาคือว่า xargs เห็นช่องว่างเป็นอาร์กิวเมนต์ใหม่วิธีการเปลี่ยนอักขระตัวคั่นที่ใช้-dหรือ-Eน่าเสียดายที่ทำงานบน Mac OS ไม่ถูกต้อง



2

เป็นหลักเทียบเท่ากับคำตอบ xargs แต่ในกรณีที่คุณต้องการประมวลผลแบบขนาน:

parallel -q cp file1 ::: /foo/ /bar/

ตัวอย่างเช่นหากต้องการคัดลอก file1 ลงในไดเรกทอรีย่อยทั้งหมดของโฟลเดอร์ปัจจุบัน (รวมถึงการเรียกซ้ำ):

parallel -q cp file1 ::: `find -mindepth 1 -type d`

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

นอกจากนี้ยังเป็นหน้าที่คล้ายกับอาร์กิวเมนต์ '-P' สำหรับ xargs


0

ไม่คุณไม่สามารถ.

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

http://github.com/ddavison/branch

ค่อนข้างง่าย -
branch myfile dir1 dir2 dir3


บ่อยครั้งที่มีสถานการณ์ที่ฉันจะเขียนสคริปต์ของตัวเอง แต่ฉันมักจะใช้เครื่องจักรจำนวนมากในทุกวันนี้ที่ทำให้พวกเขาทุกคนซิงค์ดูเหมือนว่าจะเป็นเรื่องยุ่งยาก หากมีวิธีในการเมานต์เว็บไดเรกทอรีบนคลาวด์เป็น/eเพียงแค่ครั้งเดียวในแต่ละเครื่องฉันก็สามารถเขียนเครื่องมือไฟฟ้าของตัวเองและเก็บมันไว้ตลอดไป
Evgeni Sergeev


0

สมมติว่าคุณต้องการคัดลอกfileName.txtไปยังไดเรกทอรีย่อยทั้งหมดภายในไดเรกทอรีทำงานปัจจุบัน

  1. รับชื่อไดเรกทอรีย่อยทั้งหมดlsและบันทึกเป็นไฟล์ชั่วคราวบางคำพูดallFolders.txt

    ls > allFolders.txt
  2. xargsพิมพ์รายชื่อและผ่านมันไปที่คำสั่ง

    cat allFolders.txt | xargs -n 1 cp fileName.txt

0

อีกวิธีหนึ่งคือใช้ cat และ tee ดังนี้:

cat <source file> | tee <destination file 1> | tee <destination file 2> [...] > <last destination file>

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


0

ใช้สคริปต์ทุบตี

DESTINATIONPATH[0]="xxx/yyy"
DESTINATIONPATH[1]="aaa/bbb"
                ..
DESTINATIONPATH[5]="MainLine/USER"
NumberOfDestinations=6

for (( i=0; i<NumberOfDestinations; i++))
    do
        cp  SourcePath/fileName.ext ${DESTINATIONPATH[$i]}

    done
exit

ฉันให้สิ่งนี้ downvote คำถามที่ถามเป็นการเฉพาะสำหรับโซลูชันที่ไม่วนซ้ำ
Alex Telon

-1

หากคุณต้องการคัดลอกหลาย ๆ โฟลเดอร์ไปยังหลาย ๆ โฟลเดอร์คุณสามารถทำสิ่งนี้ได้:

echo dir1 dir2 dir3 | xargs -n 1 cp -r / path / toyourdir / {subdir1, subdir2, subdir3}


-1

หากไดเรกทอรีเป้าหมายทั้งหมดของคุณตรงกับนิพจน์พา ธ - เหมือนกับไดเรกทอรีย่อยทั้งหมดpath/to- เพียงใช้findร่วมกับcpสิ่งนี้:

find ./path/to/* -type d -exec cp [file name] {} \;

แค่นั้นแหละ.


ฉันให้สิ่งนี้ downvote คำถามที่ถามโดยเฉพาะสำหรับวิธีแก้ปัญหาที่ไม่พบ
Alex Telon

ขอบคุณที่ให้ความช่วยเหลือ @AlexTelon อย่างละเอียด ฉันคิดว่าฉันพลาดบิตนั้นไป ฉันหวังว่าคุณคงเส้นคงวาเช่นกันและให้คะแนนทุกคำตอบอื่น ๆ ที่ใช้findในเธรด
Mig82

-2

หากคุณจำเป็นต้องระบุว่าโฟลเดอร์ใดที่จะคัดลอกไฟล์คุณสามารถรวมการค้นหากับ greps อย่างน้อยหนึ่งรายการ ตัวอย่างเช่นการแทนที่ favicon.ico ในโฟลเดอร์ย่อยใด ๆ ที่คุณสามารถใช้:

find . | grep favicon\.ico | xargs -n 1 cp -f /root/favicon.ico

-3

สิ่งนี้จะคัดลอกไปยังไดเรกทอรีย่อยทันทีหากคุณต้องการเจาะลึกกว่านี้ให้ปรับ-maxdepthพารามิเตอร์

find . -mindepth 1 -maxdepth 1 -type d| xargs -n 1 cp -i index.html

หากคุณไม่ต้องการคัดลอกไปยังไดเรกทอรีทั้งหมดหวังว่าคุณสามารถกรองไดเรกทอรีที่คุณไม่สนใจตัวอย่างการคัดลอกไปยังโฟลเดอร์ทั้งหมดที่ขึ้นต้นด้วย a

find . -mindepth 1 -maxdepth 1 -type d| grep \/a |xargs -n 1 cp -i index.html

หากการคัดลอกไปยังชุดไดเรกทอรีโดยพลการ / แยกจากกันคุณจะต้องมีคำแนะนำของ Robert Gamble


-3

ฉันต้องการคัดลอกไฟล์ไปยังหลายไดเรกทอรีเช่น: cp file1 /foo/; cp file1 /bar/; cp file1 /foo2/; cp file1 /bar2/ และคัดลอกไดเรกทอรีไปยังไดเรกทอรีอื่น: cp -r dir1/ /foo/; cp -r dir1/ /bar/; cp -r dir1/ /foo2/; cp -r dir1/ /bar2/

ฉันรู้ว่ามันเหมือนการออกคำสั่งหลายอย่าง แต่มันทำงานได้ดีสำหรับฉันเมื่อฉันต้องการพิมพ์ 1 บรรทัดและเดินออกไปซักพัก


7
คุณกำลังตอบคำถามอายุ 6 ปีกับอีก 15 คำตอบ คำตอบของคุณจะต้องแปลกใหม่ ความคิดเห็นของฉัน - ไม่
Craig S. Anderson

-4

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

สำหรับฉันใน $ (ls); ทำ cp sourcefile $ i; เสร็จแล้ว


คำถามบอกว่าเป็นไปได้ด้วยการวนรอบดังนั้นนี่ไม่ได้เพิ่มอะไรเลย
LJNielsenDk

downvoted อย่าพยายามแยกวิเคราะห์ผลลัพธ์ของlsและอ้างถึงตัวแปรเสมอ for i in ./*; do cp sourcefile "$i"; done
sleblanc
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.