คำสั่งของคุณจะไม่ทำงานตามที่คาดไว้ด้วยเหตุผลหลายประการ:
ทุบตีประเมิน `dirname {}`
ก่อน คำสั่ง find จะถูกเรียกใช้งาน
สิ่งนี้สามารถแก้ไขได้โดยการเรียกใช้ bash เพื่อประเมินผลลัพธ์ของ dirname
คำสั่ง
-execdir
เปลี่ยนเป็นไดเร็กทอรีของไฟล์ที่พบก่อนเรียกใช้งานคำสั่ง
ดังนั้นแม้จะมีไวยากรณ์ที่เหมาะสม dirname {}
จะเป็น .
.
เนื่องจาก find กำลังดำเนินการผ่านไฟล์ทั้งหมดภายในไดเรกทอรีทั้งหมด (แทนที่จะเป็นไดเรกทอรีเอง) การย้ายไดเรกทอรีที่กำลังประมวลผลอยู่อาจทำให้เกิดพฤติกรรมที่ไม่คาดคิด
ฉันไม่รู้พอที่จะลงรายละเอียด แต่ตัวอย่างต่อไปนี้ควรอธิบาย
$ find data -type f -printf " %p" ; echo
data/1/b data/1/a data/2/b data/2/a
$
$ find data -type f -exec bash -c ' \
> echo -n " "mv `dirname {}` backup/
> ' \; ; echo
mv data/1 backup/ mv data/1 backup/ mv data/2 backup/ mv data/2 backup/
$
$ find data -type f -exec bash -c '
> echo -n " "mv `dirname {}` backup/; mv `dirname "{}"` backup/
> ' \; ; echo
mv data/1 backup/ mv data/1 backup/
mv: cannot stat `data/1': No such file or directory
หลังจากย้ายไดเรกทอรีแล้ว data/1
ค้นหาพบว่ากำลังประมวลผลเนื้อหา ซึ่งทำให้ข้อความแสดงข้อผิดพลาดตั้งแต่ค้นหาดำเนินการ mv
สำหรับทุกไฟล์ใน data/1
แต่ทำงานได้ดีอย่างอื่น เมื่อประมวลผลเสร็จแล้ว data/1
หาได้รับ "หลงทาง" อย่างใด
ในขณะที่ค้นหาจัดการตัวละครที่เป็นไปได้ทั้งหมดที่มีความหมายพิเศษอย่างถูกต้องถ้า {}
เกิดขึ้นเป็นอาร์กิวเมนต์ธรรมดาที่จะค้นหาคำสั่งในตัวอย่าง 3 จะไม่สามารถดำเนินการได้อย่างถูกต้องหากเช่นมีช่องว่างเกิดขึ้นในเส้นทาง เพื่อหลีกเลี่ยงปัญหานี้ทั้งการส่งออกอาร์กิวเมนต์ของ dirname
จะต้องมีการยกมา
การใช้ mv "`dirname "{}"`"
(หรือ mv "$("{}")"
ซึ่งมีความชัดเจนมากขึ้น) จะทำงานได้ดีกับช่องว่าง แต่สามารถนำไปสู่ผลกระทบร้ายแรงโดยทั่วไป 1 .
mv -b
ไม่สามารถสำรองข้อมูลไดเรกทอรีได้เฉพาะไฟล์เท่านั้น
เมื่อคุณพบว่าตัวเองปัญหา 3 จะเกิดขึ้นก็ต่อเมื่อคุณพยายาม ย้าย ไดเรกทอรี แต่ไม่ใช่ถ้าคุณเช่นลบออก ดังนั้นทางออกที่ง่ายและปลอดภัยในการแก้ไขปัญหา 3 (ซึ่งแก้ไขปัญหาที่ 5 ในกระบวนการ) กำลังย้ายไดเรกทอรีที่ตรงกันลงในไฟล์ zip 2
ปัญหาที่ 4 สามารถแก้ไขได้โดยผ่าน {}
เป็นอาร์กิวเมนต์เพื่อทุบตีและเข้าถึงมันเป็น $0
.
คำสั่ง
find /converter/storage/unmatched/ -type f -size -4b -name '*.mp3' \ -exec bash -c ' \
zip -0mqr smallfiles.zip "$(dirname "$0")"\
' {} \;
จะทำงานได้ตามที่คาดไว้แม้ว่าจะยังคงสร้างข้อความแสดงข้อผิดพลาดเมื่อพยายามย้ายไดเรกทอรีมากกว่าหนึ่งครั้ง
จะใช้วิธีที่สะอาดกว่านี้ (เช่นไม่มีข้อความแสดงข้อผิดพลาด) find -depth -type d
เพื่อผ่านไดเรกทอรีเอง 3
สำหรับแต่ละไดเรกทอรีเราสามารถใช้
find "$0" -maxdepth 1 -type f -size -4b -name '*.mp3' -printf 1 -quit
ปริ้น 1 ถ้าเพียง แต่ควรลบออก 4 และทดสอบ ( [
) เพื่อตรวจสอบว่าพบพิมพ์ 1 .
คำสั่ง
find /converter/storage/unmatched/ -depth -type d -exec bash -c ' \
[ $(find "$0" -maxdepth 1 -type f -size -4b -name '*.mp3' -printf 1 -quit) ] \
&& echo zip -0mqr smallfiles.zip "$0"\
' {} \;
จะต้องมีผลที่ต้องการ
1 หากชื่อไดเรกทอรีภายใน ไม่มีที่เปรียบ ประกอบด้วยอักขระขึ้นบรรทัดใหม่หนึ่งตัว "$(dirname "{}")"
จะประเมินให้ unmatched
และ $(dirname {})
จะประเมินให้ .
(เช่นโฟลเดอร์ที่คุณเรียกใช้งานคำสั่ง)!
2 แม้จะไม่มีการบีบอัดไฟล์ แต่มันจะใช้เวลานานกว่ามากในการย้ายไฟล์ถ้าไฟล์มีขนาดใหญ่ เนื่องจากโฟลเดอร์ปลายทางของคุณถูกเรียก smallfiles ฉันสงสัยว่านี่จะไม่เป็นปัญหา
3 สวิตช์ความลึกทำให้กระบวนการค้นหาเนื้อหาของแต่ละไดเรกทอรีก่อนประมวลผลตัวไดเรกทอรี นี่เป็นการหลีกเลี่ยงข้อความแสดงข้อผิดพลาดที่เราได้รับด้วยวิธีแรก
4 -quit
สวิทช์ทำให้หยุดค้นหาหลังจากหาคู่แรก มันไม่จำเป็นอย่างเคร่งครัด แต่มันอาจเพิ่มความเร็วขึ้นเล็กน้อย
mv
ย้ายเพียงไดเรกทอรีเดียวแล้วบ่นNo such file or directory
. ฉันค่อนข้างแน่ใจว่าสิ่งนี้เกี่ยวข้องกับความเข้าใจในการค้นหาของฉัน คุณสามารถชี้ฉันไปในทิศทางที่ถูกต้องได้ไหม