ทางออกที่ดีที่สุดของฉันในปัจจุบันคือ:
for i in $(find . -name *.jpg); do echo $i; done
ปัญหา: ไม่จัดการช่องว่างในชื่อไฟล์
หมายเหตุ: ฉันจะรักวิธีการทำเช่นนี้กราฟิกเช่นคำสั่ง "ต้นไม้"
ทางออกที่ดีที่สุดของฉันในปัจจุบันคือ:
for i in $(find . -name *.jpg); do echo $i; done
ปัญหา: ไม่จัดการช่องว่างในชื่อไฟล์
หมายเหตุ: ฉันจะรักวิธีการทำเช่นนี้กราฟิกเช่นคำสั่ง "ต้นไม้"
คำตอบ:
วิธีการบัญญัติคือการทำ
find . -name '*.jpg' -exec echo {} \;
(แทนที่\;
ด้วย+
เพื่อส่งไฟล์มากกว่าหนึ่งไฟล์ต่อecho
ครั้ง)
หรือ (เฉพาะ GNU ถึงแม้ว่า BSD บางอันก็มีเหมือนกัน):
find . -name '*.jpg' -print0 | xargs -r0 echo
zsh:
for i (**/*.jpg(D)) echo $i
echo
ที่ขยายลำดับหนีเช่น\b
(อย่างน้อย Unix สอดคล้องecho
s)
find
manpage แสดงให้เห็นว่าfind . -type f -exec file '{}' \;
ในEXAMPLES
ส่วน บางทีหอยบางตัวจะจัดฟันแบบพิเศษ
'{}'
, \{\}
, {}
, "{}"
, '{'}
มีการขยายตัวเปลือก (สิ่งที่บอร์นเหมือนเปลือก) ให้เป็นหนึ่งในข้อโต้แย้งที่จะพบว่าเป็นตัวละครทั้งสอง "{" และ "}" แทนที่ "find" ด้วย "echo find" หรือprintf '<%s>\n' find
หากคุณต้องการตรวจสอบอีกครั้ง
ได้รับคำตอบที่ดีกว่าแล้ว
แต่โปรดทราบว่าช่องว่างไม่ใช่ปัญหาเดียวในรหัสที่คุณให้ แท็บอักขระขึ้นบรรทัดใหม่และอักขระตัวแทนก็เป็นปัญหาเช่นกัน
กับ
IFS='
'
set -f
for i in $(find . -name '*.jpg'); do echo "$i"; done
จากนั้นมีเพียงอักขระขึ้นบรรทัดใหม่เท่านั้นที่เป็นปัญหา
สิ่งที่คุณพูดถึงเป็นหนึ่งในปัญหาพื้นฐานที่ผู้คนเผชิญเมื่อพวกเขาพยายามอ่านชื่อไฟล์ บางครั้งผู้ที่มีความรู้ จำกัด และมีความเข้าใจผิดเกี่ยวกับโครงสร้างไฟล์และโฟลเดอร์มักจะลืมว่า " ใน UNIX Everything is a file " ดังนั้นพวกเขาจึงไม่เข้าใจว่าพวกเขาจำเป็นต้องจัดการช่องว่างเช่นกันเนื่องจากชื่อไฟล์อาจประกอบด้วย 2 คำขึ้นไปที่มีช่องว่าง
การแก้ไข:ดังนั้นวิธีหนึ่งที่รู้จักกันดีในการทำเช่นนี้คือการทำอ่านสะอาด
เราที่นี่จะอ่านไฟล์ทั้งหมดที่มีอยู่และเก็บไว้ในตัวแปรครั้งต่อไปเมื่อทำการประมวลผลที่ต้องการเราก็จะต้องให้ตัวแปรนั้นอยู่ในเครื่องหมายคำพูดซึ่งจะรักษาชื่อไฟล์ที่มีช่องว่าง นี่เป็นวิธีพื้นฐานอย่างหนึ่งในการทำเช่นนี้อย่างไรก็ตามคำตอบอื่น ๆ ที่คนอื่น ๆ ในที่ทำงานได้รับเช่นกัน
สคริปต์:
find /path/to/files/ -iname "*jpg" | \
while read I; do
cp -v --parent "$I" /backup/dir/
done
ที่นี่ฉันกำลังอ่านไฟล์โดยให้เส้นทางไปยังพวกเขาและสิ่งที่ฉันกำลังอ่านฉันกำลังทำให้พวกเขาอยู่ในตัวแปรฉันซึ่งฉันจะพูดในภายหลังในขณะที่การประมวลผลเพื่อรักษาพื้นที่เพื่อดำเนินการอย่างถูกต้อง
หวังว่าสิ่งนี้จะช่วยคุณในทางใดทางหนึ่ง
เพียงแค่มีfind
และbash
:
find . -name '*.jpg' -exec bash -c '
echo "treating file $1 in bash, from path : ${1%/*}"
' -- {} \;
ด้วยวิธีนี้เราใช้$1
ในการทุบตีเช่นในสคริปต์พื้นฐานที่เปิดมุมมองที่ดีในการดำเนินงานขั้นสูง (หรือไม่) งานใด ๆ
วิธีที่มีประสิทธิภาพมากขึ้น (เพื่อหลีกเลี่ยงการเริ่ม bash ใหม่สำหรับทุกไฟล์):
find . -name '*.jpg' -exec bash -c 'for i do
echo "treating file $i in bash, from path : ${i%/*}"
done' -- {} +
ใน bash รุ่นล่าสุดคุณสามารถใช้globstar
ตัวเลือก:
shopt -s globstar
for file in **/*.jpg ; do
echo "$file"
done
สำหรับการกระทำที่ง่ายคุณสามารถข้ามลูปได้ทั้งหมด:
echo **/*.jpg
set -G
) ก็ไม่ควรที่จะใช้ในการทุบตีเป็นรุ่นทุบตีเสียพื้นฐาน (เช่นเดียวกับ GNU grep -r
) ในขณะที่มันลงมาเป็น symlinks ไปยังไดเรกทอรี (เทียบเท่าfind -L
หรือของ zsh ***/*.jpg
) นอกจากนี้โปรดทราบว่าตรงกันข้ามกับการค้นหามันจะ ommit dotfiles และไม่ลงไปสู่ dotdirs (โดยค่าเริ่มต้น)
$i
หรือไม่ ฉันทำอย่างนั้นและมันก็ใช้ได้ดี มีบางอย่างผิดปกติกับวิธีการนี้หรือไม่?