ฉันจะดำเนินการกับไฟล์ทั้งหมดที่มีนามสกุลเฉพาะในโฟลเดอร์ย่อยอย่างสง่างามได้อย่างไร?


18

ทางออกที่ดีที่สุดของฉันในปัจจุบันคือ:

for i in $(find . -name *.jpg); do echo $i; done

ปัญหา: ไม่จัดการช่องว่างในชื่อไฟล์

หมายเหตุ: ฉันจะรักวิธีการทำเช่นนี้กราฟิกเช่นคำสั่ง "ต้นไม้"


คุณไม่สามารถใส่เครื่องหมายคำพูดไปรอบ ๆ ได้$iหรือไม่ ฉันทำอย่างนั้นและมันก็ใช้ได้ดี มีบางอย่างผิดปกติกับวิธีการนี้หรือไม่?
Umar Farooq Khawaja

คำตอบ:


26

วิธีการบัญญัติคือการทำ

find . -name '*.jpg' -exec echo {} \;

(แทนที่\;ด้วย+เพื่อส่งไฟล์มากกว่าหนึ่งไฟล์ต่อechoครั้ง)

หรือ (เฉพาะ GNU ถึงแม้ว่า BSD บางอันก็มีเหมือนกัน):

find . -name '*.jpg' -print0 | xargs -r0 echo

zsh:

for i (**/*.jpg(D)) echo $i

2
หากคุณใช้xargs -0คุณควรจับคู่มันกับfind -0
itsbruce

1
@ MichaelKjörlingไม่มีการอ้างถึง {} ไม่สร้างความแตกต่าง {} ถูกขยายโดยการค้นหาไม่ใช่เชลล์ การปรับปรุงจะไม่ใช้echoที่ขยายลำดับหนีเช่น\b(อย่างน้อย Unix สอดคล้องechos)
Stéphane Chazelas

1
@sch คุณแน่ใจหรือไม่ findmanpage แสดงให้เห็นว่าfind . -type f -exec file '{}' \;ในEXAMPLESส่วน บางทีหอยบางตัวจะจัดฟันแบบพิเศษ
QuasarDonkey

1
คำพูดไม่เป็นอันตราย แต่สร้างความแตกต่าง ทั้งหมด'{}', \{\}, {}, "{}", '{'}มีการขยายตัวเปลือก (สิ่งที่บอร์นเหมือนเปลือก) ให้เป็นหนึ่งในข้อโต้แย้งที่จะพบว่าเป็นตัวละครทั้งสอง "{" และ "}" แทนที่ "find" ด้วย "echo find" หรือprintf '<%s>\n' findหากคุณต้องการตรวจสอบอีกครั้ง
Stéphane Chazelas


2

ได้รับคำตอบที่ดีกว่าแล้ว

แต่โปรดทราบว่าช่องว่างไม่ใช่ปัญหาเดียวในรหัสที่คุณให้ แท็บอักขระขึ้นบรรทัดใหม่และอักขระตัวแทนก็เป็นปัญหาเช่นกัน

กับ

IFS='
'
set -f
for i in $(find . -name '*.jpg'); do echo "$i"; done

จากนั้นมีเพียงอักขระขึ้นบรรทัดใหม่เท่านั้นที่เป็นปัญหา


1

สิ่งที่คุณพูดถึงเป็นหนึ่งในปัญหาพื้นฐานที่ผู้คนเผชิญเมื่อพวกเขาพยายามอ่านชื่อไฟล์ บางครั้งผู้ที่มีความรู้ จำกัด และมีความเข้าใจผิดเกี่ยวกับโครงสร้างไฟล์และโฟลเดอร์มักจะลืมว่า " ใน UNIX Everything is a file " ดังนั้นพวกเขาจึงไม่เข้าใจว่าพวกเขาจำเป็นต้องจัดการช่องว่างเช่นกันเนื่องจากชื่อไฟล์อาจประกอบด้วย 2 คำขึ้นไปที่มีช่องว่าง

การแก้ไข:ดังนั้นวิธีหนึ่งที่รู้จักกันดีในการทำเช่นนี้คือการทำอ่านสะอาด

เราที่นี่จะอ่านไฟล์ทั้งหมดที่มีอยู่และเก็บไว้ในตัวแปรครั้งต่อไปเมื่อทำการประมวลผลที่ต้องการเราก็จะต้องให้ตัวแปรนั้นอยู่ในเครื่องหมายคำพูดซึ่งจะรักษาชื่อไฟล์ที่มีช่องว่าง นี่เป็นวิธีพื้นฐานอย่างหนึ่งในการทำเช่นนี้อย่างไรก็ตามคำตอบอื่น ๆ ที่คนอื่น ๆ ในที่ทำงานได้รับเช่นกัน

สคริปต์:

 find /path/to/files/ -iname "*jpg" | \
  while read I; do
   cp -v --parent "$I" /backup/dir/
  done

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

หวังว่าสิ่งนี้จะช่วยคุณในทางใดทางหนึ่ง


1
"ทุกอย่างเป็นไฟล์" หมายถึงอย่างอื่น โซลูชันของคุณเฉพาะ GUN และไม่รองรับเครื่องหมายแบ็กสแลชหรืออักขระบรรทัดใหม่ในชื่อไฟล์ "ในขณะที่อ่าน" การวนรอบในเชลล์ (IMO) มักจะเป็นตัวบ่งชี้การฝึกสคริปต์ที่ไม่ดีของเชลล์
Stéphane Chazelas

@sch: ฮะและฉันเคยคิดว่ามันก็โอเค ขอบคุณที่ชี้ให้เห็นว่าฉันอาจต้องดูอีก
The Dark Knight

ขออภัยฉันหมายถึง "GNU" ไม่ใช่ "GUN" ด้านบน (เป็นครั้งแรกที่ฉันรู้ว่าเป็นแอนนาแกรม BTW ... )
Stéphane Chazelas

1

เพียงแค่มี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' -- {} +

0

ใน bash รุ่นล่าสุดคุณสามารถใช้globstarตัวเลือก:

shopt -s globstar
for file in **/*.jpg ; do
    echo "$file"
done

สำหรับการกระทำที่ง่ายคุณสามารถข้ามลูปได้ทั้งหมด:

echo **/*.jpg

ในขณะที่ทำงานใน zsh (ที่คุณลักษณะนี้มาจาก) และ ksh93 (กับset -G) ก็ไม่ควรที่จะใช้ในการทุบตีเป็นรุ่นทุบตีเสียพื้นฐาน (เช่นเดียวกับ GNU grep -r) ในขณะที่มันลงมาเป็น symlinks ไปยังไดเรกทอรี (เทียบเท่าfind -Lหรือของ zsh ***/*.jpg) นอกจากนี้โปรดทราบว่าตรงกันข้ามกับการค้นหามันจะ ommit dotfiles และไม่ลงไปสู่ ​​dotdirs (โดยค่าเริ่มต้น)
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.