ค้นหา -exec ในสคริปต์ทุบตีพร้อมส่วนขยายตัวแปร


14

ฉันพยายามเรียกใช้คำสั่งคล้ายกับคำสั่งด้านล่างในสคริปต์ทุบตี มันควรจะค้นหาผ่านโฟลเดอร์ย่อยทั้งหมดและคัดลอกไฟล์ทั้งหมดของบางประเภทให้อยู่ในระดับรากของ$sourcedir$targetdir

#!/bin/bash

# These are set as arguments to the script, not hard-coded
sourcedir="/path/to/sourcedir"
targetdir="/path/to/targetdir"

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2/`basename "$1"`"' "{}" "$targetdir" \;

นี้ดูเหมือนว่าจะสวยใกล้เคียงยกเว้นว่า{}จะไม่ถูกส่งผ่านไปในขณะที่$2ไป-exec sh -c ...

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

แก้ไข:ฉันเห็นคนแนะนำให้ใช้xargsหรือการผูกมัดข้อโต้แย้ง ฉันอยู่ภายใต้การแสดงผลว่านี่เป็นเพียงข้อโต้แย้งที่ จำกัด ตัวอย่างเช่นถ้าฉันมีไฟล์. jpg หลายพันไฟล์ที่ฉันพยายามคัดลอกจากไดเรกทอรีแกลเลอรี่จำนวนมากไปยังไดเรกทอรีสไลด์โชว์ยักษ์โซลูชั่นการเชื่อมโยงจะยังคงใช้งานได้หรือไม่

แก้ไข 2:ปัญหาของฉันคือฉันหายไป_ก่อนที่ตัวเลือกแรกของฉันที่จะดวลจุดโทษใน-execคำสั่ง สำหรับทุกคนที่สงสัยเกี่ยวกับวิธีทำให้คำสั่ง find ทำงานได้เพิ่ม_และทุกอย่างจะดีขึ้น:

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;

ฉันยอมรับคำตอบด้านล่างแล้วว่าทำได้ดีกว่า แต่มีประสิทธิภาพและสวยงามกว่า


4
นั่นคือเหตุผลที่xargsเคยสร้างมาเพื่อจัดการข้อโต้แย้งจำนวนมากโดยอัตโนมัติในคำสั่งปกติที่มีข้อ จำกัด นอกจากนี้เพื่อพิจารณาข้อ จำกัด สูงสุดของอาร์กิวเมนต์ส่วนใหญ่ได้รับการปรับปรุงอย่างมากสำหรับอุปกรณ์มาตรฐานของ GNU นอกจากนี้คุณยังจะได้รับประโยชน์จากประสิทธิภาพการทำงานโดยหลีกเลี่ยงการดำเนินการตามกระบวนการทั้งหมดซึ่งเกี่ยวข้องกับไฟล์นับพันที่เกี่ยวข้อง
JM Becker

ด้วย gnu-find และ + แทนที่จะเป็น ";" คุณสามารถจัดการกับอาร์กิวเมนต์หลายตัวพร้อมกันด้วย find ได้ และคุณบันทึกอาร์กิวเมนต์ที่ซับซ้อนผ่าน -print0
ผู้ใช้ไม่ทราบ

@userunknown: ฉันกำลังตอบกลับด้านล่างคำตอบของคุณ
JM Becker

@ ผู้ใช้ที่ไม่รู้จักดีฉันรักรหัสนี้ อย่างน้อยเป็นไปตาม POSIXอย่างเต็มที่และจะทำงานได้โดยไม่ต้องมี GNU ทุกอย่างในเครื่องเลย มีบรรดาครั้งเมื่อคุณไม่ต้องนี้โดยเฉพาะอย่างยิ่งบนเซิร์ฟเวอร์ที่ทำงาน
ไวยากรณ์

คำตอบ:


6

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

find "$sourcedir" -type f -name "*.type" | xargs cp -t targetdir

หากคุณต้องการจัดการชื่อไฟล์พิเศษให้ใช้NULLเป็นตัวคั่นของคุณ

find "$sourcedir" -type f -name "*.type" -print0 | xargs -0 cp -t "$targetdir"

1
สำหรับกรณีที่สองอย่าลืมเพิ่ม-print0ไปยังfindและ-0ไปxargs
SiegeX

@ SiegeX ได้ทำไปแล้วก่อนที่ฉันจะสังเกตเห็นความคิดเห็นของคุณ
JM Becker

นอกจากนี้NULLไม่จำเป็นถ้าคุณใช้'{}'มันสำคัญเมื่อคุณไม่ ผลประโยชน์ที่แท้จริงระหว่างอีกสิ่งหนึ่งนอกเหนือจากการPOSIXปฏิบัติตามกฎระเบียบคือประสิทธิภาพ
JM Becker

6

คุณต้องผ่าน{}เป็นอาร์กิวเมนต์ให้กับเชลล์แล้ววนรอบแต่ละอาร์กิวเมนต์

find "$sourcedir" -type f -name "*.type" -exec sh -c 'for f; do cp "$f" "$0"; done' "$targetdir" {} +

หมายเหตุ : วิธีการทำงานคืออาร์กิวเมนต์แรกของเชลล์คือชื่อของเชลล์เราสามารถใช้ประโยชน์จากการส่งชื่อโดยใช้ชื่อ$targetdirและจากนั้นใช้พารามิเตอร์พิเศษ$0ภายในเชลล์สคริปต์เพื่อเข้าถึง targetdir


1
"$targetdir"ไม่ถูกขยายในเครื่องหมายคำพูดเดี่ยว
enzotib

5

หากคุณไม่เชื่อในโบสถ์ xargs:

find "$sourcedir" -type f -name "*.mp3" -exec cp -t "$targetdir" {} +

คำอธิบาย:

cp -t a b c d 

คัดลอก b, c และ d ไปยังเป้าหมาย dir

-exec cmd {} +

เรียกใช้คำสั่งบนไฟล์จำนวนมากพร้อมกันไม่ใช่หนึ่งไฟล์หลังจากไฟล์อื่น (ซึ่งเป็นมาตรฐานหากคุณใช้";"แทน+) นี่คือสาเหตุที่ต้องดึงเป้าหมายไปข้างหน้าและทำเครื่องหมายอย่างชัดเจนว่าเป็นเป้าหมาย

สิ่งนี้ใช้ได้กับ gnu-find และอาจไม่เหมาะสำหรับการใช้งานการค้นหาอื่น ๆ แน่นอนมันขึ้นอยู่กับ -t-flag ด้วย

TechZilla เป็นหลักสูตรที่ถูกต้องเนื่องจากshไม่จำเป็นต้องเรียกใช้ cp

หากคุณไม่ได้ใช้xargsซึ่งส่วนใหญ่ไม่จำเป็นต้องใช้ร่วมกับfindคุณจะได้รับการบันทึกจากการเรียนรู้-print0และ-0ตั้งค่าสถานะ


1
ซึ่งวิธีการที่ทุกคนอาจชอบนั้นเป็นอัตวิสัย จากที่กล่าวมามีเหตุผลที่ยังคงใช้xargsอยู่ ตัวอย่างที่ใหญ่ที่สุดจะเกิดอะไรขึ้นถ้าคุณไม่ค้นหาไฟล์ ฉันใช้ xargs แทนการforวนรอบตลอดเวลาfindมีขนาดเล็กกว่ามาก นอกจากนี้findสนับสนุนเฉพาะ+ถ้าคุณใช้ GNU findมันไม่ได้กำหนดไว้ใน POSIX ดังนั้นในขณะที่คุณควรจะชอบfindอยู่คนเดียว แต่ก็ไม่ได้ทำทุกสิ่งที่ xargs ทำ เมื่อคุณพิจารณา GNU xargsคุณจะได้รับ-Pมัลติคอร์ด้วยเช่นกัน เรียนรู้คุณค่าของมันxargsโดยไม่คำนึงถึง
JM Becker

ความคิดเห็นของฉันแตกต่างอย่างชัดเจน ในทางกลับกันคำตอบของคุณก็ถูกต้องเช่นกัน เป็นหนึ่งในโซลูชันที่ดีที่สุดที่มีอยู่
JM Becker

@TechZilla: ฉันหวังว่าจะจำได้ว่าจะเยี่ยมชมเว็บไซต์นี้อีกครั้งเมื่อการค้นหาเริ่มสนับสนุนการเรียกใช้แบบขนาน :) ในกรณีส่วนใหญ่ที่มีการคัดลอก / ย้ายความเร็วของดิสก์จะเป็นปัจจัย จำกัด แต่ SSD อาจเปลี่ยนภาพ คุณพูดถูกสิ่งที่ไม่ใช่ GNU-solution ที่จะให้นั้นเป็นเรื่องที่ดี อื่น ๆ โซลูชันการค้นหานั้นสั้นกว่าง่ายกว่าและใช้กระบวนการเพียงสองกระบวนการเท่านั้น
ผู้ใช้ไม่ทราบ

0
read -p "SOURCE: " sourcedir
read -p "TYPE: " type
read -p "TARGET: " targetdir
find -L $sourcedir -iname "*.$type" -exec cp -v {} $targetdir \;

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