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


12

คำถามนี้เป็นผลสืบเนื่องของทุกคำถามก่อนหน้านี้ฉันสร้างไดเรกทอรีต่าง ๆ mkdirนานาโดยใช้

ฉันกำลังใช้bashเปลือก ฉันสร้างไดเรกทอรีห้าสิบรายการโดยเริ่มต้นด้วยคำนำหน้า "s" โดยใช้คำสั่ง:

mkdir $(printf "s%02i " $(seq 1 50))

ซึ่งใช้ตัวเลขเป็นศูนย์ที่สองพร้อมเลขศูนย์ นั่นคือไดเรกทอรีที่ผมได้รับเป็นของแบบฟอร์มs01, ,s02 ... ,s49s50

ตอนนี้ฉันต้องการใช้cpเพื่อคัดลอกไฟล์เดียว (ตัวอย่างtest.txt) ไปยังแต่ละไดเรกทอรีห้าสิบ เป็นไปได้ไหมที่จะทำสิ่งนี้ในลักษณะที่คล้ายคลึงกับที่กล่าวมา ตัวอย่างเช่นงานต่อไปนี้จะทำงานอย่างไร ฉันค่อนข้างใหม่กับ Unix / Linux ดังนั้นฉันจึงไม่ต้องการลองนี้จนกว่าจะมีคนโปรดให้ฉันบ่งบอกว่ามันปลอดภัย

cp test.txt $ (printf "s% 02i.txt" $ (seq 1 50))

มองไปที่manหน้าcpนั้นดูเหมือนจะไม่cpรองรับหลายปลายทางเช่นนี้อย่างไรก็ตาม:

NAME
       cp - copy files and directories

SYNOPSIS
       cp [OPTION]... [-T] SOURCE DEST
       cp [OPTION]... SOURCE... DIRECTORY
       cp [OPTION]... -t DIRECTORY SOURCE...

DESCRIPTION
       Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

       Mandatory  arguments  to  long  options are mandatory for short options
       too.

คำตอบ:


7

หากคุณต้องการใช้เอาต์พุตจากคำสั่งของคุณเพื่อคัดลอกไฟล์ไปยังแต่ละไดเรกทอรีโดยใช้cpคุณสามารถไปที่xargs:

printf "s%02i " $(seq 1 50) | xargs -n 1 cp test.txt

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

หรือสมมติว่าไดเรกทอรีมีอยู่แล้วคุณสามารถลองดังนี้:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -print0 | xargs -0 -I {} cp test.txt {}

หรือไม่มีท่อ:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -exec cp test.txt {} \;

คำสั่งสองคำสั่งสุดท้ายจะค้นหาไฟล์ใด ๆ ในไดเรกทอรีปัจจุบันและไฟล์cp test.txtเหล่านั้น -maxdepth 1ตัวเลือกที่จะหลีกเลี่ยงการไดเรกทอรีย่อยใด ๆ ที่ได้รับไฟล์ได้เป็นอย่างดี จะเตือนว่า's[0-9][0-9]'คือการจับคู่กับsตามด้วยตัวเลขสองหลักใด ๆ ซึ่งหมายความว่าหากมีเหตุผลบางอย่างที่คุณมีs99ในก็ยังจะได้รับสำเนาของcwdtest.txt


8

คุณสามารถปล่อยให้เชลล์ทำการวนซ้ำด้วยการforวนซ้ำ นี่เป็นวิธีพื้นฐานที่สุดที่ไม่พึ่งพาเครื่องมือภายนอกเช่นparallelหรือxargsและฉันคิดว่ามันง่ายที่สุดที่จะเข้าใจ:

for name in $(printf "s%02i " $(seq 1 50)); do
    mkdir $name
    cp test.txt $name
done

มีอีกหลายล้านวิธีในการเขียนเช่น:

for name in $(seq -w 1 50); do
    mkdir s$name
    cp test.txt s$name
done

หากคุณต้องการตรวจสอบสิ่งที่จะดำเนินการก่อนที่จะทำคุณสามารถทำสิ่งที่ต้องการเตรียมคำสั่งด้วยechoซึ่งจะพิมพ์บรรทัดแทนที่จะดำเนินการ:

for name in $(seq -w 1 50); do
    echo mkdir s$name
    echo cp test.txt s$name
done

เอาท์พุท:

mkdir s01
cp test.txt s01
mkdir s02
cp test.txt s02
mkdir s03
cp test.txt s03
# etc.


2

คุณสามารถใช้ GNU ขนานได้เช่นกัน สมมติว่าคุณอยู่ในไดเรกทอรีที่มี text.txt และ 50 dirs ของคุณอยู่ใน/my/50dirs/path(ชอบ/my/50dirs/path/s01, /my/50dirs/path/s02ฯลฯ ) ที่คุณจะเรียกใช้:

seq -w 01 50 | parallel -j1 cp text.txt /my/50dirs/path/s{}

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