find: อาร์กิวเมนต์ที่ขาดหายไปถึง -exec


18

ฉันพยายามเรียกใช้คำสั่งต่อไปนี้:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' +

นี่กำลังส่งคืนข้อผิดพลาด:

find: missing argument to -exec

ฉันไม่เห็นว่ามีอะไรผิดปกติกับคำสั่งนี้เนื่องจากดูเหมือนจะตรงกับหน้าคน:

คำสั่ง -exec {} +

ตัวแปรของตัวเลือก -exec นี้จะรันคำสั่งที่ระบุในไฟล์ที่เลือก แต่บรรทัดคำสั่งจะถูกสร้างขึ้นโดยการต่อท้ายชื่อไฟล์ที่เลือกแต่ละชื่อที่ท้าย จำนวนรวมของคำสั่งจะน้อยกว่าจำนวนไฟล์ที่ตรงกัน บรรทัดคำสั่งถูกสร้างขึ้นในลักษณะเดียวกับที่ xargs สร้างบรรทัดคำสั่ง อนุญาตเพียงหนึ่งอินสแตนซ์ของ '{}' ภายในคำสั่ง คำสั่งจะถูกดำเนินการในไดเรกทอรีเริ่มต้น

ฉันก็ลอง:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' '{}' +
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar '{}' +
find a/folder b/folder \( -name *.c -o -name *.h \) -exec grep -I foobar '{}' +
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+

คุณได้ลองหลบหนี+ในตอนท้ายหรือไม่? find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
jayhendren

3
คุณอาจจะใช้รุ่นเก่า findGNU แม้ว่า-exec cmd {} +ตัวแปรคือ POSIX และมีให้บริการตั้งแต่ยุค 80 แต่ GNU พบว่าเพิ่งเพิ่ม (ค่อนข้าง) เมื่อเร็ว ๆ นี้ (2005) สิ่งที่ไม่find --versionบอกคุณ?
Stéphane Chazelas

2
@ Koveras นั่นน่าจะเป็นแบบนั้น -exec {} +ถูกเพิ่มใน 4.2.12 ในปี 2005 ใน GNU ที่เก่ากว่าพบว่าคุณสามารถใช้ (ไม่ใช่ POSIX) -print0 | xargs -r0เพื่อให้ได้สิ่งที่คล้ายกัน 4.1คือตั้งแต่ปี 1994
Stéphane Chazelas

1
ชี้คำตอบที่ถูกลบไปแล้วว่าคำพูดของ-nameรูปแบบควรถูกยกมา: -name "*.c" -o -name "*.h". สิ่งนี้เป็นจริงแม้ว่าจะไม่เกี่ยวข้องกับ-execข้อผิดพลาด คุณจะสังเกตเห็นว่าคำตอบอื่น ๆ ทั้งหมดใส่สัญลักษณ์แทนลงในเครื่องหมายอัญประกาศแม้ว่า Gilles จะพูดถึงมันเท่านั้น … (ต่อ)
G-Man พูดว่า 'Reinstate Monica'

1
(ต่อ) …คำตอบของ jlliagre ยุบนิพจน์ชื่อเป็น-name "*.[ch]"โดยไม่มีคำอธิบาย -oซึ่งมีประโยชน์ในการลดความซับซ้อนของบรรทัดคำสั่งและโดยเฉพาะกำจัด ค้นหานิพจน์ที่เกี่ยวข้อง-oนั้นยากที่จะทำให้ถูกต้อง ของคุณผิด หากคำสั่งของคุณได้รับการแก้ไขเพื่อไม่ให้เกิดข้อผิดพลาด (เช่นในคำตอบของ Gilles) คำสั่งนั้นจะทำงานgrepเฉพาะ.hไฟล์เท่านั้น '(' -name '*.c' -o -name '*.h' ')'ที่คุณต้องทำ
G-Man กล่าวว่า 'Reinstate Monica'

คำตอบ:


18

{}คุณจำเป็นต้องเอาคำพูดเดียวที่คุณใช้ไปรอบ ๆ คำสั่งสามารถทำให้ง่ายขึ้นเช่นนี้:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +

คุณควรใช้ GNU รุ่นเก่าในการค้นหารุ่นนี้หรือไม่

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \;

โอ๊ะโอพวกเขาตั้งใจที่จะเป็นคำพูดไม่ได้เป็น backticks
David Kennedy

คำพูดจะไร้ประโยชน์เพราะ{}ไม่มีความหมายเฉพาะกับเปลือก
jlliagre

จากหน้าค้นหาของมนุษย์: "สตริง '{}' ถูกแทนที่ด้วยชื่อไฟล์ปัจจุบันที่ถูกประมวลผลทุกที่มันเกิดขึ้นในอาร์กิวเมนต์ของคำสั่งไม่ใช่เฉพาะในอาร์กิวเมนต์ที่อยู่คนเดียวเช่นเดียวกับในบางรุ่นของการค้นหา การสร้างอาจต้องหลบหนี (ด้วย '\') หรืออ้างเพื่อปกป้องพวกเขาจากการขยายตัวโดยเปลือก "
David Kennedy

1
แน่นอนฉันอ่านมันในหน้าคู่มือ แต่ความจริงก็คือไม่มีเปลือกฉันรู้ว่าต้องมีการอ้างอิงวงเล็บปีกกา คุณใช้เปลือกอะไร
jlliagre

ทุบตี. มีหรือไม่มีคำพูดฉันได้รับข้อผิดพลาดต่อไป
David Kennedy

10

“ อาร์กิวเมนต์ที่หายไปถึง-exec” มักจะหมายความว่าการโต้แย้งไป - execไม่มีจุดสิ้นสุด เทอร์มิต้องเป็นข้อโต้แย้งที่มีเพียงตัวละคร;(ซึ่งจะต้องมีการอ้างในคำสั่งเชลล์จึงมักจะเขียน\;หรือ';') หรือสองข้อโต้แย้งต่อเนื่องที่มีและ{}+

สเตฟาน Chazelas มีการระบุว่าคุณกำลังใช้รุ่นเก่าของ GNU หาที่ไม่สนับสนุนเท่านั้น-exec … {} + -exec {} \;แม้ว่า GNU เป็นผู้ใช้ช้า-exec … {} +แต่ฉันขอแนะนำให้คุณใช้ชุดเครื่องมือโบราณน้อยกว่า (เช่นCygwinซึ่งรวมถึง git และอีกมากมายหรือGNUwin32ซึ่งไม่มี git แต่ไม่มีความพยายามของพนักงานที่ไม่ดี - to-use-linux-but-we-impose-windows vibe ที่ Cygwin ให้) ฟีเจอร์นี้เพิ่มเข้ามาในเวอร์ชั่น 4.2.12 เมื่อ 9 ปีที่แล้ว (เป็นฟีเจอร์ที่ระบุล่าสุดเพื่อให้findเป็นไปตามข้อกำหนดของGNU POSIX)

หากคุณต้องการที่จะติดเก่า GNU หาคุณสามารถใช้-print0กับการxargs -0ที่จะได้รับการทำงานที่คล้ายกัน: การจัดกลุ่มการเรียกคำสั่งสนับสนุนชื่อไฟล์โดยพลการ

find a/folder b/folder -name '*.c' -o -name '*.h' -print0 | xargs -0 grep -I foobar /dev/null

อ้างถึงสัญลักษณ์แทนในfindบรรทัดคำสั่งเสมอ มิฉะนั้นหากคุณบังเอิญเรียกใช้คำสั่งนี้จากไดเรกทอรีที่มี.cไฟล์คำสั่งunquoted *.cจะถูกขยายไปยังรายการ.cไฟล์ในไดเรกทอรีปัจจุบัน

การเพิ่ม/dev/nullไปยังgrepบรรทัดคำสั่งเป็นเคล็ดลับเพื่อให้แน่ใจว่า grep จะพิมพ์ชื่อไฟล์เสมอแม้ว่าจะfindเกิดขึ้นเพื่อค้นหาคู่ที่ตรงกัน ด้วย GNU -Hหาวิธีอื่นคือการผ่านตัวเลือก


1
คุณหมายถึงอะไรโดยพนักงานไม่ดีพยายามที่จะใช้ลินุกซ์ - แต่ - เรา - กำหนด - หน้าต่าง - บรรยากาศที่ cygwin ให้?
David Kennedy

GNUwin32 ไม่ได้คาดหวัง :(
David Kennedy

ดูความคิดเห็นของฉันในคำถาม
G-Man กล่าวว่า 'Reinstate Monica'

เครื่องหมายคำพูดรอบกึ่งทำงานจากสคริปต์ package.json
bvj

2

หากมีคำสั่งเช่น

find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar {} +

ส่งคืนข้อผิดพลาด

find: missing argument to -exec

สาเหตุน่าจะเป็น GNU เก่าเกินไปซึ่งไม่สนับสนุนไวยากรณ์find -exec mycommand {} +ในกรณีนั้นการทดแทนที่มีประสิทธิภาพต่ำคือการรัน-exec mycommand {} \;ซึ่งจะรันmycommandครั้งเดียวสำหรับเป้าหมายที่พบทุกชุดแทนที่จะรวบรวมเป้าหมายหลายชุดและเรียกใช้mycommandเพียงครั้งเดียว

อย่างไรก็ตาม GNU findไม่รองรับเช่น

find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +

เพราะ GNU findสนับสนุนเฉพาะการรวมตัวอักษรแทนการทั่วไปมากขึ้น{} + {} additional parameters +โปรดทราบว่าไม่มีสิ่งใดระหว่างวงเล็บปีกกาและ+ตัวละคร หากคุณลองสิ่งนี้คุณจะได้รับข้อผิดพลาดเดียวกัน:

find: missing argument to -exec

วิธีแก้ปัญหาคือการใช้ไวยากรณ์{} additional parameters \;ที่ใช้งานได้ แต่จะดำเนินการคำสั่งหนึ่งครั้งสำหรับเป้าหมายที่พบทุกครั้ง หากคุณต้องการประสิทธิภาพที่มากขึ้นด้วย GNU findคุณต้องเขียนสคริปต์ตัวตัดคำที่สามารถผนวกพารามิเตอร์เพิ่มเติมเข้ากับอาร์กิวเมนต์ที่กำหนด สิ่งที่ต้องการ

#!/bin/bash
exec mycommand "$@" additional parameters

ควรจะดีพอ หรือถ้าคุณไม่ต้องการสร้างไฟล์ชั่วคราวคุณสามารถใช้หนึ่งซับเพื่อเปลี่ยนลำดับของพารามิเตอร์ดังนี้:

find . -type f -and -name "*.ttf" -exec bash -c 'mycommand "$@" extra arguments' {} +

mycommand {list of ttf files} extra argumentsซึ่งจะดำเนินการ โปรดทราบว่าคุณอาจต้องหลีกเลี่ยงสองอักขระพิเศษสำหรับ bash หลังจากการ-cตั้งค่าสถานะ


(1) ส่วนต่าง ๆ ข้างต้นที่ตอบคำถามของคนอื่นแล้ว (2) สิ่งที่คุณจะอธิบายไม่ได้เป็นข้อบกพร่องหรือมีความบกพร่องใน GNU findแต่พฤติกรรมที่ถูกต้องตามที่ระบุไว้ POSIX
G-Man กล่าวว่า 'Reinstate Monica'

1
+1 ในที่สุดคนที่ตอบว่าทำไมพารามิเตอร์เพิ่มเติมไม่ทำงาน! ดูเหมือนว่าจะมีข้อบกพร่องในนิยาม POSIX
Jonathan

หากคุณได้ GNU findคุณอาจได้ cpGNU ในกรณีนี้คุณสามารถfind ... -exec cp --target-directory ~/.fonts {} +เก็บไว้{}ในตอนท้ายของสตริงการดำเนินการ
roaima

1

find . -type f -perm 0777 -exec chmod 644 {}\;

find: missing argument to ``-exec'ข้อผิดพลาดได้

การเพิ่มช่องว่างระหว่าง{}และ\แก้ไขมัน:

find . -type f -perm 0777 -print -exec chmod 644 {} \;


1
ไม่มีปัญหาดังกล่าวในfindคำสั่งในคำถามที่อยู่ในมือ
Kusalananda

ในคำถามมันไม่เป็นไรที่ฉันเข้าใจ แต่ปัญหาเหมือนกันคือ "find: อาร์กิวเมนต์ที่หายไปกับ` `-exec '" ปัญหาสามารถเกิดขึ้นได้จากเหตุผลที่แตกต่างกัน -2 ฉันตอบเพราะฉันเห็นคำแถลงปัญหาเดียวกัน
ShreePool

@ Kusalananda ความเศร้าโศกที่ดี noob ได้จัดหาวิธีแก้ปัญหาสำหรับรายงานข้อผิดพลาดซึ่งระบุโดย OP ในทั้งชื่อและเนื้อหาของคำถาม
bvj

@bvj คำถามที่เกี่ยวข้องกับ+รูปแบบของ-execตัวเลือกที่findชัดเจน คำตอบนี้แก้ไขปัญหาที่ผู้ใช้ถามคำถามไม่ได้
Kusalananda

-1

ฉันมีอาการปวดหัวร่วมกับไวยากรณ์ exec ในอดีต วันนี้ฉันชอบไวยากรณ์ bash ของ nicer มากกว่า:

for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done

มันมีข้อ จำกัด บางอย่างเมื่อคุณต้องการจัดการกับไฟล์เป็นกลุ่มเนื่องจากแต่ละไฟล์จะถูกประเมินตามลำดับ แต่คุณสามารถไพพ์เอาต์พุตที่อื่นได้


1
ในขณะที่สิ่งนี้มีแนวโน้มที่จะทำงานมันมีประโยชน์น้อยกว่ารุ่น pure-find เนื่องจากไม่สามารถจัดการไฟล์ที่มีช่องว่างในชื่อได้อย่างถูกต้อง
Etan Reisner

5
ไม่ไม่ทำเช่นนี้ สิ่งนี้จะหยุดพักทันทีที่ไฟล์มีช่องว่างและอักขระ“ แปลก” อื่น ๆ สิ่งนี้มีความซับซ้อนและช้ากว่าfind … -exec … \;ดังนั้นจึงไม่มีเหตุผลที่จะใช้สิ่งนี้แม้ว่าคุณจะรู้ว่าชื่อไฟล์ของคุณเชื่องแล้ว
Gilles 'หยุดความชั่วร้าย' Gilles

สิ่งนี้มีประโยชน์สำหรับสถานการณ์ของฉันที่ฉันต้องการเรียกใช้ตรรกะหลายบรรทัดตามชื่อไฟล์ (เช่นลบตัวอักษรสร้างไดเรกทอรีและย้ายไฟล์) การพยายามทำหลายสิ่งหลายอย่างในครั้งเดียวexecทำให้ปวดหัวมากเกินไปเป็นเวลา 5 นาทีที่ฉันต้องการใช้เวลากับเรื่องนี้ ชื่อไฟล์ของฉันถูกทำให้เชื่องและสิ่งนี้แก้ปัญหาของฉันได้ :)
4322
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.