เป็นไปได้หรือไม่ที่จะวางซ้อน 'find -exec' ภายใน 'find -exec' อื่น?


14

สิ่งต่อไปนี้คือสิ่งที่ฉันเป็น แต่รหัสของฉันไม่ทำงานไม่ว่าฉันจะหลบหนี{}และ+ ;

find ./ -maxdepth 1 -type d -name '.*' -exec \
    find {} -maxdepth 1 -type f -name '*.ini' -exec \
        md5sum \{\} \\; \;

หลังจากเห็นคำถาม Unix - & - Linuxนี้ฉันพบว่าโค้ดต่อไปนี้ใช้งานได้ แต่ไม่พบการซ้อนกันและฉันสงสัยว่ามีวิธีที่ดีกว่าในการทำงานนี้โดยเฉพาะ

find ./ -maxdepth 1 -type d -name '.*' \
-exec bash -c 'for x; do
    find "$x" -maxdepth 1 -type f -name "*.ini" \
    -exec md5sum \{\} \;; \
done' _ {} \+

มีวิธีการทำรังfind -execโดยไม่จำเป็นต้องเรียกเปลือกหอย (ดังกล่าวข้างต้น) ด้วยการอ้างและหลบหนีข้อ จำกัด ทั้งหมดหรือไม่?

หรือสิ่งนี้สามารถทำได้โดยตรงในคำสั่งค้นหาเดียวโดยใช้การผสมผสานของพารามิเตอร์จำนวนมาก?


4
แม้ว่ามันจะเป็นไปได้ที่จะทำสิ่งที่คุณถามเมื่อสิ่งต่าง ๆ มีความซับซ้อนฉันก็เปลี่ยนไปใช้เชลล์หรือสคริปต์ Perl ข้อมูลโค้ดที่สองของคุณกำลังทำสิ่งนี้อยู่โดยเฉพาะกับเชลล์สคริปต์แบบอินไลน์ ผู้กล้าหาญคนหนึ่งมีความบันเทิง แต่พวกเขายากที่จะเข้าใจและยากที่จะรักษา เว้นแต่ว่านี่เป็นข้อตกลงแบบนัดเดียวที่คุณยังคงได้รับอย่างดีฉันก็ไม่เห็นเหตุผลที่ดีที่จะทำสิ่งอื่นนอกเหนือจากการท้าทายทางปัญญา
Warren Young

1
@Warren หนุ่ม: แน่นอนฉันไม่คิดว่าเป็นแนวคิดที่ซับซ้อน แต่ผมถือว่าคุณหมายถึงไม่มีง่ายวิธีการทำด้วยfindแต่ถ้าfindไม่สามารถทำเช่นนี้แล้วทำไมfindจึงเคารพนับถือ (?)เป็นยืด การใช้งานสำหรับการค้นหาไฟล์? ... ฉันพบว่า subseqeuntly ใช้find ./ -maxdepth 2 -path '.*/*.ini' -type f -exec md5sum {} \+งานได้ดีในสถานการณ์ของฉัน (การอ้างอิงของ jw013 เพื่อ-pruneนำฉันไปที่นี้ในหน้าคน) แต่ฉันสงสัยว่ามันเป็นวิธีที่มีประสิทธิภาพ (ในจำพวก) ฉันไม่เคยใช้จริง ๆfind(ในเวลาน้อยกว่าหนึ่งปีของ Linux) อย่างที่locateทำเกือบทั้งหมดที่ฉันต้องการ
Peter.O

1
การ-pathทดสอบเป็นสิ่งที่ฉันอยากจะแนะนำ ด้วยสิ่งนี้คุณควรจะสามารถทำทุกสิ่งที่คุณต้องการ (ขออภัยสำหรับสมาคม Ace Of Base;))
rozcietrzewiacz

คำตอบ:


8

ฉันจะลองใช้การค้นหาเดียวเช่น:

find .*/ -maxdepth 1 -type f -name '*.ini' -execdir md5sum {} +

หรือแม้กระทั่ง (ไม่findเลยเพียงแค่ทำให้กลมกล่อม)

md5sum .*/*.ini

แม้ว่าสิ่งนี้จะขาดการ-type fตรวจสอบดังนั้นจะใช้ได้เฉพาะในกรณีที่คุณไม่มีไดเรกทอรี / ไม่ใช่ไฟล์ที่ลงท้าย.iniด้วย ถ้าคุณทำคุณสามารถใช้

for x in .*/*.ini; do 
    if [ -f "$x" ]; then 
        md5sum "$x"
    fi
done

ซึ่งจะสูญเสียความได้เปรียบของการร้องขอ md5sum เพียงครั้งเดียว

แก้ไข

สำหรับวิธีผูกมัดแบบทั่วไปและปลอดภัยfindคุณสามารถทำอะไรบางอย่างเช่น

find <paths> <args> -print0 | xargs -0 -I{.} find {.} <args for second find> [etc.]

ฉันได้รับข้อผิดพลาดด้วย-fและแล้วความผิดพลาดอีกด้วย (ฉ?) -execdir.. เมื่อฉันเปลี่ยน-execdirกับ -exec และ / หรือยังเปลี่ยน md5sum พิมพ์ผมได้รับอะไร ..
Peter.O

ขอบคุณสำหรับทางเลือก ... แต่ฉันใช้วิธีนี้มากขึ้นในการใช้find... มันไม่มากนักที่ฉันต้องการให้ตัวอย่างนี้ได้รับการแก้ไขฉันกำลังมองหาข้อมูลเชิงลึกเกี่ยวกับวิธีการค้นหา -fu .. . อาจมีปุยมากกว่า Fu ในการค้นหา .. (ฉันไม่รู้เพราะฉันแทบไม่เคยใช้มัน) และนี่เป็นสถานการณ์แรกที่ฉันต้องการใช้มันจริงๆ (สำหรับไฟล์รูปภาพจริง) และ - คุณสมบัติที่ฉันได้ยินมามากดูเหมือนจะไม่ได้มีประสิทธิภาพเท่ากับตัวแทน (?) ถึง ... (+1 สำหรับทางเลือกแม้ว่า) .. .. แต่findตัวอย่างของคุณไม่ทำงาน (ยัง )
Peter.O

ฉันได้รับข้อผิดพลาดนี้สำหรับfindคำสั่ง: ... find: The relative path ~ / bin 'รวมอยู่ในตัวแปรสภาพแวดล้อม PATH ซึ่งไม่ปลอดภัยเมื่อใช้ร่วมกับการดำเนินการ -execdir ของการค้นหา โปรดลบรายการนั้นออกจาก $ PATH` .... ดังนั้นอาจใช้งานได้ แต่ฉันต้องบอกว่าฉันพยายามกำจัด ~ / bin ไปสักพักแล้วตอนนี้ ... ฉันจะต้องใช้เวลามากกว่านี้ ดูจริงจังนะ ... ฉันไม่รู้ว่าฉันตั้งไว้ที่ไหน ... ความคิดใด ๆ ที่อาจซ่อนอยู่ ~/binในเส้นทางของฉัน
Peter.O

ฉันคิดว่าพลังของการfindชื่นชมที่ดีที่สุดในสถานการณ์ที่ไม่สามารถทำได้โดยสิ้นเชิงกับ globs แต่เนื่องจากสถานการณ์เหล่านั้นเป็นของหายากฉันไม่จำเป็นต้องพบมากตามปกติ
jw013

โอเค .. นั่นเป็นจุดที่น่าสนใจและดี (เกี่ยวกับการใช้ globs) ...
Peter.O

2

ปัญหาเดิมของคุณไม่ต้องการการโทรหาซ้ำ แต่ฉันคิดว่านั่นไม่ใช่ประเด็น

ฉันเชื่อว่าไม่สามารถโทรหาแบบเรียกซ้ำในแบบที่คุณต้องการ

ต่อไปนี้ไม่ได้เรียกหา recursively (หรือการทำรังสิ่งที่เรียกว่า) อย่างใดอย่างหนึ่ง แต่คุณไม่สามารถใช้ชุดผลลัพธ์ของการค้นหาครั้งแรกและป้อนไปยังที่สองได้หรือไม่ นี่คือวิธีที่ฉันจะทำโดยสัญชาตญาณ:

find `find ./ -maxdepth 1 -type d -name '.*'` \
    -maxdepth 1 -type f -name '*.ini' -exec md5sum {} \;

คุณสามารถใช้xargsสำหรับการดำเนินการค้นหาครั้งที่สอง

ปรับปรุง:

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

md5sum `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`

เมื่อทำแบ็คทิกเกอร์ซ้อนคุณเพียงเพิ่มแบ็กสแลชข้าง\หน้าข้างใน

หากเราจินตนาการว่าmd5sumใช้อาร์กิวเมนต์ชื่อไฟล์เพียงรายการเดียวเราสามารถสรุปเป็นforวงได้ตลอดเวลา:

for f in `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`
do
    md5sum $f
done

โปรดทราบว่าสิ่งนี้จะยากขึ้นหากชื่อไฟล์ / ไดเรกทอรีที่ขึ้นต้นด้วย-หรือมีช่องว่างมีส่วนเกี่ยวข้อง ยูทิลิตี UNIX ไม่สามารถเล่นกับมันได้ ในกรณีที่การเพิ่ม./, --หรือคำพูดเป็นสิ่งจำเป็น

เห็นได้ชัดว่าตัวอย่างดั้งเดิมไม่ใช่ตัวอย่างที่ดีเพราะเราทำได้:

md5sum .*/*.ini

1
คุณได้รับภาพรวมที่ดีของสถานการณ์ แต่วิธีการทั้งหมดที่แสดงfindได้รับข้อผิดพลาดเมื่อไฟล์ / ไดเรกทอรีมีช่องว่าง ... การmd5sum .*/*.iniทำงานได้ดี ... ฉันเริ่มรู้สึกทั่วไป * Warren Young's * แสดงความคิดเห็นเกี่ยวกับสิ่งที่ได้รับ 'ซับซ้อน' สำหรับfindเกิดขึ้นในช่วงต้นเกม :) แต่ฉันคิดว่าfindมันเข้ามาในตัวของมันเองเมื่อการทดสอบสภาพมีความซับซ้อนมากขึ้น ดูเหมือนว่ามีวิธีที่ง่ายกว่าในการทำ .. (แต่ Perl ไม่ใช่ "ง่าย" สำหรับฉัน (ยัง) ...
Peter.O

0

อย่างน้อยฉันจัดการเพื่อซ้อน 2 ค้นหาคำสั่ง:

find ~ -maxdepth 1 -type d -name '.*' -execdir \
    find {} -maxdepth 1 -type f -name '*.ini' \;

แต่ฉันไม่ได้แก้ปัญหาที่จะเรียกอีก -exec (dir) - โทรจากที่นั่น


ใช่ว่าเป็นปัญหาของฉันว่า :)
Peter.O

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