ฉันจะค้นหาล้มเหลวได้อย่างไรหาก -exec ล้มเหลว


29

เมื่อฉันเรียกใช้คำสั่งนี้ในเปลือก (ในไดเรกทอรีที่ไม่ว่าง):

find . -exec invalid_command_here {} \;

ฉันได้รับสิ่งนี้:

find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory

(และอื่น ๆ สำหรับแต่ละไฟล์)

ฉันต้องfindล้มเหลวหลังจากข้อผิดพลาดแรก มีวิธีใดบ้างที่จะทำให้เรื่องนี้ใช้งานได้? ฉันไม่สามารถใช้งานได้xargsเนื่องจากฉันมีช่องว่างในเส้นทางของฉัน แต่ฉันต้องการสคริปต์ที่เรียกสิ่งนี้เพื่อส่งคืนรหัสข้อผิดพลาด

คำตอบ:


34

นี่เป็นข้อ จำกัด findของ มาตรฐาน POSIXระบุว่าสถานะการกลับมาของfindคือ 0 เว้นแต่จะมีข้อผิดพลาดเกิดขึ้นในขณะที่ภายในไดเรกทอรี; สถานะการส่งคืนของคำสั่งที่ดำเนินการจะไม่ถูกป้อนเข้าไป

คุณสามารถทำให้คำสั่งเขียนสถานะลงในไฟล์หรือไปที่ descriptor:

find_status_file=$(mktemp findstatus)
: >"$find_status_file"
find  -exec sh -c 'trap "echo \$?" EXIT; invalid_command "$0"' {} \;
if [ -s "$find_status_file" ]; then
  echo 1>&2 "An error occurred"
fi
rm -f "$find_status_file"

อีกวิธีที่คุณค้นพบคือการใช้ xargs xargsคำสั่งเสมอประมวลผลไฟล์ทั้งหมด แต่กลับสถานะ 1 ถ้ามีคำสั่งผลตอบแทนสถานะภัณฑ์

find  -print0 | xargs -0 -n1 invalid_command

อีกวิธีหนึ่งคือการหลีกเลี่ยงfindและใช้การวนซ้ำแบบซ้ำในเชลล์แทน: **/หมายถึงความลึกของไดเรกทอรีย่อย ต้องใช้เวอร์ชัน 4 หรือสูงกว่าของ bash; macOS ค้างอยู่ที่รุ่น 3.x ดังนั้นคุณต้องติดตั้งจากคอลเลกชันพอร์ต ใช้set -eเพื่อหยุดสคริปต์ในคำสั่งแรกคืนสถานะที่ไม่ใช่ศูนย์

shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done

ระวังว่าใน bash 4.0 ถึง 4.2 มันจะทำงานได้ แต่ traverses ลิงก์สัญลักษณ์ไปยังไดเร็กตอรี่ซึ่งมักจะไม่ต้องการ

หากคุณใช้ zsh แทนทุบตีการวนซ้ำแบบซ้ำจะออกจากกล่องโดยไม่มี gotchas Zsh พร้อมใช้งานตามค่าเริ่มต้นใน OSX / macOS ใน zsh คุณสามารถเขียนได้

set -e
for x in **/*.xml; do invalid_command "$x"; done

xargsวิธีการทำงานโดยทั่วไป แต่อย่างใดแบ่งในbash -cคำสั่ง ตัวอย่างเช่นfind . -name '*.xml' -print0 | xargs -0 -n 1 -I '{}' bash -c "foo {}". นี่จะถูกดำเนินการหลายครั้งในขณะที่find . -name '2*.xml' -print0 | xargs -0 -n 1 -I '{}' foo {}ถูกดำเนินการเพียงครั้งเดียวและล้มเหลว มีความคิดอะไรไหม
DKroot

@DKroot ไม่เคยใช้งานภายใน{} bash -cใช้ชื่อไฟล์และแทรกโดยตรงในคำสั่งเชลล์ หากชื่อไฟล์มีอักขระที่มีความหมายพิเศษในเชลล์เช่นช่องว่างเชลล์จะตีความอักขระพิเศษเหล่านี้เช่น หากคุณต้องการเชลล์ให้ส่ง{}เป็นอาร์กิวเมนต์แยกเช่นbash -c 'foo "$0"' {}(สังเกตเครื่องหมายอัญประกาศคู่ล้อมรอบ$0ด้วย)
Gilles 'หยุดความชั่วร้าย'

ตกลงอ้างคำถามกันทำไมข้อผิดพลาดต่อไปนี้ไม่หยุดใน? find . -name '*' -print0 | xargs -0 -n 1 -I '{}' bash -c 'foo "$0"' {}
DKroot

@DKroot ทำไมมันจะหยุดข้อผิดพลาด? xargs จะรันคำสั่งในทุกรายการ
Gilles 'หยุดความชั่วร้าย'

ฉันพยายามใช้คำตอบนี้: วิธี xargs ( find . -print0 | xargs -0 -n1 invalid_command) สิ่งนี้จะหยุดในข้อผิดพลาดแรกอย่างถูกต้อง: find . -name '*' -print0 | xargs -0 -n 1 -I '{}' foo {}. ที่ดี! แต่วิธีการเดียวกันนี้ใช้ไม่ได้กับbash -c(ด้านบน) bash -cข้อแตกต่างระหว่างสองคือ
DKroot


4

xargsเป็นทางเลือกหนึ่ง อย่างไรก็ตามมันง่ายมากที่จะทำเช่นนี้ด้วยการfindใช้+แทน\;

-exec  utility_name  [argument ...]   {} +

จากเอกสาร POSIX :

หากการแสดงออกหลักถูกคั่นด้วยเครื่องหมายบวกหลักจะประเมินเป็นจริงเสมอและชื่อพา ธ ที่การประเมินหลักจะถูกรวมเป็นชุด ยูทิลิตี้ Utility_name จะถูกเรียกใช้หนึ่งครั้งสำหรับชื่อพา ธ รวมแต่ละชุด การร้องขอแต่ละครั้งจะเริ่มต้นหลังจากชื่อพา ธ สุดท้ายในชุดรวมและจะแล้วเสร็จก่อนที่ยูทิลิตี้ค้นหาจะออกและก่อนชื่อพา ธ แรกในชุดถัดไป (ถ้ามี) จะถูกรวมสำหรับหลักนี้ แต่ไม่ระบุว่าเป็นการเรียก เกิดขึ้นก่อนระหว่างหรือหลังการประเมินผลของพรรคอื่น ๆ หากการเรียกใช้คืนค่าที่ไม่เป็นศูนย์เป็นสถานะออกยูทิลิตี find จะส่งคืนสถานะการออกที่ไม่เป็นศูนย์อาร์กิวเมนต์ที่มีเพียงอักขระสองตัว“ {}” จะถูกแทนที่ด้วยชุดของชื่อพา ธ รวมโดยแต่ละชื่อพา ธ จะถูกส่งผ่านเป็นอาร์กิวเมนต์แยกไปยังยูทิลิตีที่เรียกใช้ในลำดับเดียวกันกับที่รวมเข้าด้วยกัน ขนาดของชื่อพา ธ สองชื่อหรือมากกว่านั้นจะถูก จำกัด ดังนั้นการเรียกใช้ยูทิลิตี้จะไม่ทำให้เกินขีด จำกัด {ARG_MAX} ของระบบ หากมีมากกว่าหนึ่งอาร์กิวเมนต์ที่มีเพียงอักขระสองตัว“ {}” ปรากฏอยู่พฤติกรรมจะไม่ถูกระบุ

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