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


206

ฉันได้รับความช่วยเหลือในวันนี้ด้วยคำสั่ง แต่ดูเหมือนจะไม่ทำงาน นี่คือคำสั่ง:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {}\;

เชลล์ส่งคืน

find: missing argument to `-exec'

สิ่งที่ฉันพยายามทำโดยทั่วไปคือไปที่ไดเรกทอรีซ้ำ (ถ้ามีไดเรกทอรีอื่น) และเรียกใช้คำสั่ง ffmpeg กับ.rmประเภทไฟล์และแปลงเป็น.mp3ประเภทไฟล์ เมื่อเสร็จแล้วให้ลบ.rmไฟล์ที่เพิ่งถูกแปลง

ฉันขอขอบคุณความช่วยเหลือในเรื่องนี้

คำตอบ:


340

-execคำสั่งจะต้องถูกยกเลิกด้วย;(ดังนั้นคุณจะต้องพิมพ์\;หรือ';'เพื่อหลีกเลี่ยงการ interpretion จากเปลือก) +หรือ ข้อแตกต่างคือด้วย;คำสั่งจะเรียกหนึ่งครั้งต่อไฟล์โดยเรียกว่าคำสั่ง+เพียงสองสามครั้ง (ปกติหนึ่งครั้ง แต่มีความยาวสูงสุดสำหรับบรรทัดคำสั่งดังนั้นจึงอาจถูกแยกออก) ด้วยชื่อไฟล์ทั้งหมด . ดูตัวอย่างนี้:

$ cat /tmp/echoargs
#!/bin/sh
echo $1 - $2 - $3
$ find /tmp/foo -exec /tmp/echoargs {} \;
/tmp/foo - -
/tmp/foo/one - -
/tmp/foo/two - -
$ find /tmp/foo -exec /tmp/echoargs {} +
/tmp/foo - /tmp/foo/one - /tmp/foo/two

คำสั่งของคุณมีข้อผิดพลาดสองประการ:

ก่อนอื่นให้คุณใช้{};แต่;จะต้องเป็นพารามิเตอร์ของตัวเอง

&&ประการที่สองคำสั่งปลายที่ คุณระบุ“ run find และหากประสบความสำเร็จให้ลบไฟล์ที่มีชื่อ{};” หากคุณต้องการที่จะใช้สิ่งที่เปลือกในคำสั่งที่คุณต้องทำงานอย่างชัดเจนในเปลือกเช่น-exec-exec sh -c 'ffmpeg ... && rm'

อย่างไรก็ตามคุณไม่ควรเพิ่ม {} ภายในคำสั่ง bash มันจะสร้างปัญหาเมื่อมีอักขระพิเศษ คุณสามารถส่งพารามิเตอร์เพิ่มเติมไปยังเชลล์แทนได้-c command_string(ดูman sh):

$ ls
$(echo damn.)
$ find * -exec sh -c 'echo "{}"' \;
damn.
$ find * -exec sh -c 'echo "$1"' - {} \;
$(echo damn.)

คุณเห็น$สิ่งที่ประเมินโดยเชลล์ในตัวอย่างแรก ลองนึกภาพว่ามีไฟล์ชื่อ$(rm -rf /):-)

(หมายเหตุด้านข้าง: -ไม่จำเป็น แต่ตัวแปรแรกหลังจากคำสั่งถูกกำหนดให้กับตัวแปร$0ซึ่งเป็นตัวแปรพิเศษตามปกติที่มีชื่อของโปรแกรมที่กำลังเรียกใช้และการตั้งค่าพารามิเตอร์เป็นสิ่งสกปรกเล็กน้อยแม้ว่ามันจะชนะ อาจก่อให้เกิดอันตรายใด ๆ ที่นี่ดังนั้นเราจึงกำหนดให้เป็นเพียง-และเริ่มต้นด้วย$1)

ดังนั้นคำสั่งของคุณอาจเป็นอะไรก็ได้

find -exec bash -c 'ffmpeg -i "$1" -sameq "$1".mp3 && rm "$1".mp3' - {} \;

แต่มีวิธีที่ดีกว่าคือ หาการสนับสนุนandและดังนั้นคุณอาจจะทำสิ่งที่ชอบor find -name foo -or -name barแต่นั่นก็ยังทำงานได้ด้วย-execซึ่งประเมินว่าเป็นจริงหากคำสั่งออกจากที่สำเร็จและเป็นเท็จหากไม่ ดูตัวอย่างนี้:

$ ls
false  true
$ find * -exec {} \; -and -print
true

มันจะทำงานพิมพ์ถ้าคำสั่งก็ประสบความสำเร็จซึ่งมันสำหรับแต่ไม่ได้สำหรับtruefalse

ดังนั้นคุณสามารถใช้สองคำสั่ง exec ที่ถูกล่ามโซ่ด้วย-andและมันจะดำเนินการหลังถ้าอดีตถูกเรียกใช้ประสบความสำเร็จ


3
กุญแจดูเหมือนจะเป็นบรรทัดของ Marian "the; is arg บนตัวของมันเอง" นั่นคือสิ่งที่ทำให้ฉันหลอดไฟฉลาดและสำหรับตัวอย่างโค้ดของฉัน ขอบคุณ
pjammer

3
นั่นเป็นคำอธิบายที่ดีที่สุดที่ฉันได้อ่านใน -exec มันมีประสิทธิภาพมาก แต่ฉันมักจะพบว่ามันยากที่จะได้รับไวยากรณ์ที่เหมาะสมสำหรับมัน นี่ทำให้บางสิ่งที่ชัดเจนยิ่งขึ้น การห่อคำสั่งในเชลล์แยกโดยเฉพาะ ดี ขอบคุณ
Eurospoofer

3
โปรดทราบว่า-andและ-orไม่พกพาได้ POSIX ระบุ-aและ-o , และในความ-aเป็นจริงจะสันนิษฐานเสมอ
gniourf_gniourf

นอกจากนี้จะต้องมีช่องว่างก่อนที่จะสิ้นสุด อดีต"\;"ไม่ทำงาน แต่" \;"ทำไม่ได้
frmdstryr

56

ฉันคิดออกตอนนี้ เมื่อคุณต้องการเรียกใช้คำสั่งสองคำสั่งใน exec ในการค้นหาคุณจะต้องมีสองคำสั่งแยกกัน ในที่สุดก็ใช้งานได้สำหรับฉัน

find . -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 \; -exec rm {} \;

ไม่แน่ใจว่ามันจะทำให้ตัวแปรของไฟล์ถูกลบหรือไม่? ใครรู้ว่าเป็นกรณีนี้หรือไม่
Abs

7
ในการทดสอบสิ่งต่าง ๆ เพียงแค่เพิ่มechoคำสั่งก่อนหน้าและดูว่ามันทำอะไร
Marian

2
@Marian echoค่อนข้างไม่น่าเชื่อถือ - คุณไม่สามารถบอกความแตกต่างระหว่างecho "one argument"และecho one argument(ผลลัพธ์ของหลังเป็นเท็จเนื่องจากจริง ๆ แล้วผ่านechoอาร์กิวเมนต์ทั้งสองแยกกันโดยสิ้นเชิง) ดีกว่าที่จะทำสิ่งที่ชอบ-exec bash -c 'printf "%q " "$@"' _ ffmpeg -i {} -sameq {}.mp3 \; -printf '\n'ซึ่งจะพิมพ์เอาต์พุตในลักษณะที่ทำให้มองเห็นอักขระที่ไม่สามารถพิมพ์ได้เพื่อให้คุณสามารถตรวจจับการขึ้นบรรทัดใหม่ของ DOS และสิ่งแปลกประหลาดอื่น ๆ
Charles Duffy

52

ลองวางช่องว่างหน้า \;

ผลงาน:

find . -name "*.log" -exec echo {} \;

ไม่ทำงาน:

find . -name "*.log" -exec echo {}\;

1
การเดินทางครั้งนี้ทำให้ฉันค่อนข้างบ่อย หนึ่งวันนี้ฉันจะเพิ่มช่องว่างตามค่าเริ่มต้น
harperville

สำหรับฉันมันใช้งานได้ตรงกันข้ามใน Cygwin ภายใต้ Windows 7: ไม่มีที่ว่างก่อน \; ใช้ได้กับพื้นที่ - ไม่ได้ แต่ถ้าฉันลบ \, โดยเว้นวรรคก่อน; มันใช้งานได้และไม่มีที่ว่างก่อน มันไม่เพียงเป็นวิธีที่อธิบายไว้ที่นี่
ดูแลเว็บ

7

สำหรับข้อมูลของคุณ:
ฉันเพิ่งลองใช้คำสั่ง "find -exec" บนระบบ Cygwin (UNIX emulated บน Windows) และที่นั่นดูเหมือนว่าแบ็กสแลชก่อนเซมิโคลอนจะต้องถูกลบออก:
find ./ -name "blabla" -exec wc -l {} ;


ฉันสับสนจริงๆ find /etc/nginx -name '*.conf' -exec echo {} ;และfind /etc/nginx -name '*.conf' -exec echo {}\;ให้ผลลัพธ์เดียวกัน :(
Kirby

ฉันใช้ Bash shell ที่มาพร้อมกับ Git สำหรับ Windows และคำตอบของ Dustin Cowles นั้นเหมาะกับฉัน ในคำอื่น ๆ : {}คำพูดที่ไม่ทับขวาหนีอัฒภาคช่องว่างหลัง
mamacdon

ไม่มีความหมายแตกต่างกัน แต่ในบางกรณีคุณจำเป็นต้องใส่แบ็กสแลชในบางกรณีคุณไม่สามารถใส่มันและในกรณีอื่น ๆ ที่คุณอาจเลือก
Dominique

2

ในกรณีที่ทุกคนเห็น "arex -exec args" ที่คล้ายกันในสคริปต์ Opsworks ของ Amazon Opsworks Chef ฉันต้องเพิ่มแบ็กสแลชอีกอันเพื่อหลบหนี \;

bash 'remove_wars' do
  user 'ubuntu'
  cwd '/'
  code <<-EOH
    find /home/ubuntu/wars -type f -name "*.war" -exec rm {} \\;
  EOH
  ignore_failure true
end

2

นอกจากนี้หากผู้อื่นมี "find: ไม่มีอาร์กิวเมนต์สำหรับ -exec" สิ่งนี้อาจช่วยได้:

ในเชลล์บางตัวคุณไม่จำเป็นต้องทำการหลบหนีนั่นคือคุณไม่จำเป็นต้องใช้ "\" ต่อหน้า ";"

find <file path> -name "myFile.*" -exec rm - f {} ;

2
การ;ไม่อ้างหรือหลบหนีที่นี่หมายความว่าเชลล์สามารถใช้งานได้โดยที่เชลล์ไม่สามารถอ่านfindได้ นอกจากนี้-fและ- fเป็นสองสิ่งที่แตกต่างกัน
Charles Duffy


0

ทั้ง {} และ && จะทำให้เกิดปัญหาเนื่องจากการขยายโดยบรรทัดคำสั่ง ฉันขอแนะนำให้ลอง:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i \{} -sameq \{}.mp3 \; -exec rm \{} \;

หากคำสั่งแรกใน exec ประสบความสำเร็จและคำสั่งที่สองใน exec ถูกดำเนินการมันจะยังสามารถเข้าถึง {}ตัวแปรเพื่อลบไฟล์ที่ถูกต้องได้หรือไม่?
Abs

thinik คุณ{}ขยายอะไรไปบ้าง ยกเว้นว่ามันมีสองจุดหรือเครื่องหมายจุลภาคที่จะอยู่ตามเดิม
Marian

0

คุณต้องใส่ช่องว่างระหว่าง{}และ\;

ดังนั้นคำสั่งจะเป็นดังนี้:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {} \;

-4

หากคุณยังคงได้รับ "ค้นหา: ไม่มีอาร์กิวเมนต์ไปยัง -exec" ให้ลองตัดอาร์กิวเมนต์เรียกใช้เป็นอัญประกาศ

find <file path> -type f -exec "chmod 664 {} \;"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.