ค้นหา -exec cmd {} + vs | xargs


115

อันไหนมีประสิทธิภาพมากกว่าไฟล์ชุดใหญ่มากและควรใช้?

find . -exec cmd {} +

หรือ

find . | xargs cmd

(สมมติว่าไม่มีตัวตลกในชื่อไฟล์)


ที่เกี่ยวข้อง: stackoverflow.com/questions/9612090/…
Mateusz Piotrowski

คำตอบ:


107

ความแตกต่างของความเร็วจะไม่มีนัยสำคัญ

แต่คุณต้องแน่ใจว่า:

  1. สคริปต์ของคุณจะไม่คิดว่าไม่มีไฟล์ใดที่จะมีช่องว่างแท็บ ฯลฯ ในชื่อไฟล์ รุ่นแรกปลอดภัยรุ่นที่สองไม่ใช่

  2. สคริปต์ของคุณจะไม่ถือว่าไฟล์ที่ขึ้นต้นด้วย " -" เป็นตัวเลือก

ดังนั้นรหัสของคุณควรมีลักษณะดังนี้:

find . -exec cmd -option1 -option2 -- {} +

หรือ

find . -print0 | xargs -0 cmd -option1 -option2 --

เวอร์ชันแรกนั้นสั้นกว่าและเขียนง่ายกว่าเนื่องจากคุณสามารถเพิกเฉยต่อ 1 ได้ แต่เวอร์ชันที่สองนั้นพกพาได้และปลอดภัยกว่าเนื่องจาก " -exec cmd {} +" เป็นตัวเลือกที่ค่อนข้างใหม่ในการค้นหา GNU (ตั้งแต่ปี 2005 ระบบที่ทำงานอยู่จำนวนมากจะยังไม่มี) และมันก็เป็นรถเมื่อเร็ว ๆ นี้ นอกจากนี้ผู้คนจำนวนมากไม่ทราบ " -exec cmd {} +" ดังที่คุณเห็นจากคำตอบอื่น ๆ


4
-print0 ยังเป็นตัวเลือก GNU find (และ GNU xargs) ซึ่งขาดหายไปจากระบบที่ไม่ใช่ Linux จำนวนมากดังนั้นอาร์กิวเมนต์การพกพาจึงไม่ถูกต้อง ใช้ -print เพียงและออกจาก -0 ออกจาก xargs แต่เป็นแบบพกพามาก
dannysauer

7
ประเด็นก็คือหากไม่มี -print0 จะไม่ทำงานหากมีไฟล์ที่มีช่องว่างหรือแท็บเป็นต้นซึ่งอาจเป็นช่องโหว่ด้านความปลอดภัยราวกับว่ามีชื่อไฟล์เช่น "foo -o index.html" จากนั้น -o จะได้รับการปฏิบัติ เป็นตัวเลือก ลองในไดเร็กทอรีว่าง: "touch - foo \ -o \ index.html; find. | xargs cat" คุณจะได้รับ: "cat: invalid option - 'o'"
Tometzky

2
ตัวอย่างของเขาคือชื่อไฟล์ที่มี - หากไม่มี -print0 ค้นหาจะคาย. /foo -o index.html ดังนั้นอาจจะเริ่มต้นด้วย - ไม่ใช่เรื่องใหญ่ แต่ผลลัพธ์ที่ได้มีการเปลี่ยนแปลงเล็กน้อยและในระบบผู้ใช้หลายคนอาจให้เวกเตอร์การโจมตีหากสคริปต์ของคุณสามารถอ่านได้ทั่วโลก
bobpaul

2
หมายเหตุเกี่ยวกับบางสิ่งที่ทำให้ฉันสะดุดที่นี่ - การใช้execจะแสดงผลลัพธ์ตามที่พบในขณะที่xargsดูเหมือนว่ารอจนกว่าจะค้นหาไดเรกทอรีทั้งหมดก่อนที่จะเขียนถึง stdout หากคุณกำลังลองสิ่งนี้ในไดเร็กทอรีขนาดใหญ่และดูเหมือนว่าxargsจะไม่ได้ผลขอแนะนำให้ใช้ความอดทน
FarmerGedden

1
@Motivated Without -print0find ส่งคืนชื่อไฟล์ที่คั่นด้วยขึ้นบรรทัดใหม่ แต่การขึ้นบรรทัดใหม่ยังสามารถเป็นส่วนหนึ่งของชื่อไฟล์ทำให้ไม่ชัดเจน ไบต์ 0 ไม่ได้ดังนั้นจึงเป็นตัวคั่นที่ปลอดภัย ใช่ - การเพิ่ม--คำสั่งที่สนับสนุนเป็นแนวทางปฏิบัติที่ดีเมื่อคุณไม่สามารถควบคุมอาร์กิวเมนต์ได้แม้ว่าจะไม่จำเป็นอย่างเคร่งครัดหรือไม่ปลอดภัยก็ตาม
Tometzky

7
find . | xargs cmd

มีประสิทธิภาพมากขึ้น (วิ่งcmdน้อยที่สุดเท่าที่จะเป็นไปได้ซึ่งแตกต่างจากexecที่ทำงานcmdครั้งเดียวในแต่ละนัด) อย่างไรก็ตามคุณจะประสบปัญหาหากชื่อไฟล์มีช่องว่างหรืออักขระขี้ขลาด

แนะนำให้ใช้สิ่งต่อไปนี้:

find . -print0 | xargs -0 cmd

สิ่งนี้จะใช้งานได้แม้ว่าชื่อไฟล์จะมีอักขระขี้ขลาด ( -print0ทำให้findพิมพ์การจับคู่ที่สิ้นสุดด้วย NUL -0ทำให้xargsคาดว่าจะมีรูปแบบนี้)


28
นี่ไม่ใช่ "find. -exec cmd {} \;" แต่ "find. -exec cmd {} +" หลังจะไม่เรียกใช้ทีละไฟล์
Tometzky

2
โปรดทราบว่าxargsวิธีนี้จะช้าลงอย่างมากหากไม่มีไฟล์ที่ตรงกัน (หรือเพียงไม่กี่ไฟล์) และcmdไม่มีอะไรให้ทำมากนักสำหรับแต่ละไฟล์ ตัวอย่างเช่นเมื่อรันในไดเร็กทอรีว่างxargsเวอร์ชันจะใช้เวลาอย่างน้อยสองเท่าเนื่องจากต้องเริ่มกระบวนการสองกระบวนการแทนที่จะเป็นเพียงกระบวนการเดียว (ใช่ความแตกต่างมักมองไม่เห็นใน * nix แต่ในการวนซ้ำอาจมีความสำคัญหรือลองใช้ Windows สักระยะ ... )
SamB

2

xargsเวอร์ชันสมัยใหม่มักรองรับการดำเนินการไปป์ไลน์แบบขนาน

เห็นได้ชัดว่ามันอาจเป็นจุดหมุนเมื่อต้องเลือกระหว่าง find … -exec และ … | xargs

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