find: argumen yang hilang ke -exec

206

Saya dibantu hari ini dengan perintah, tetapi sepertinya tidak berhasil. Ini perintahnya:

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

Shell kembali

find: missing argument to `-exec'

Apa yang saya coba lakukan pada dasarnya adalah melalui direktori secara rekursif (jika memiliki direktori lain) dan menjalankan perintah ffmpeg pada .rmtipe file dan mengubahnya menjadi .mp3tipe file. Setelah ini selesai, hapus .rmfile yang baru saja dikonversi.

Saya menghargai bantuan apa pun dalam hal ini.

Abs
sumber

Jawaban:

340

Sebuah -execperintah harus diakhiri dengan ;(sehingga Anda biasanya perlu mengetik \;atau ';'untuk menghindari interpretion oleh shell) atau +. Perbedaannya adalah bahwa dengan ;, perintah dipanggil sekali per file, dengan +, ia dipanggil beberapa kali mungkin (biasanya sekali, tetapi ada panjang maksimum untuk baris perintah, sehingga mungkin terpecah) dengan semua nama file . Lihat contoh ini:

$ 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

Perintah Anda memiliki dua kesalahan:

Pertama, Anda menggunakan {};, tetapi ;harus menjadi parameter sendiri.

Kedua, perintah berakhir di &&. Anda menentukan "run find, dan jika itu berhasil, hapus file bernama {};.". Jika Anda ingin menggunakan shell stuff di -execperintah, Anda perlu menjalankannya secara eksplisit di shell, seperti -exec sh -c 'ffmpeg ... && rm'.

Namun Anda tidak boleh menambahkan {} di dalam perintah bash, itu akan menghasilkan masalah ketika ada karakter khusus. Sebagai gantinya, Anda dapat meneruskan parameter tambahan ke shell setelah -c command_string(lihat man sh):

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

Anda melihat $hal dievaluasi oleh shell pada contoh pertama. Bayangkan ada file bernama $(rm -rf /):-)

(Catatan: Ini -tidak diperlukan, tetapi variabel pertama setelah perintah ditugaskan ke variabel $0, yang merupakan variabel khusus yang biasanya berisi nama program yang sedang dijalankan dan menetapkan bahwa ke parameter sedikit najis, meskipun ia menang mungkin menyebabkan kerusakan apa pun di sini, jadi kami mengaturnya agar adil -dan mulai dengan $1.)

Jadi perintahmu bisa seperti itu

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

Tetapi ada cara yang lebih baik. menemukan dukungan anddan or, jadi Anda dapat melakukan hal-hal seperti find -name foo -or -name bar. Tapi itu juga bekerja dengan -exec, yang bernilai true jika perintah berhasil keluar, dan false jika tidak. Lihat contoh ini:

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

Hanya menjalankan cetakan jika perintah berhasil, yang dilakukan untuk truetetapi tidak untuk false.

Jadi, Anda dapat menggunakan dua pernyataan exec yang dirantai dengan -and, dan itu hanya akan mengeksekusi yang kedua jika yang pertama dijalankan dengan sukses.

Marian
sumber
3
Kuncinya tampaknya adalah garis Marian tentang "; adalah argumen sendiri" itulah yang melakukannya untuk saya, bola lampu bijaksana dan untuk sampel kode saya. Terima kasih.
pjammer
3
Itu tentang deskripsi terbaik yang pernah saya baca di -exec. Ini sangat kuat tetapi saya selalu merasa sulit untuk mendapatkan sintaks yang tepat untuk itu. Ini membuat beberapa hal menjadi lebih jelas. Terutama membungkus perintah di shell terpisah. Bagus. Terima kasih.
Eurospoofer
3
Perhatikan itu -anddan -ortidak portabel. POSIX menentukan -adan-o , dan pada kenyataannya -aselalu diasumsikan (karenanya tidak diperlukan).
gniourf_gniourf
Juga harus ada spasi sebelum terminator. Ex "\;"tidak bekerja tetapi " \;"tidak
frmdstryr
56

Saya menemukan jawabannya sekarang. Ketika Anda perlu menjalankan dua perintah di exec dalam menemukan Anda harus benar-benar memiliki dua eksekutif terpisah. Ini akhirnya berhasil untuk saya.

find . -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 \; -exec rm {} \;
Abs
sumber
Tidak yakin apakah itu akan membuat variabel file dihapus? Adakah yang tahu jika ini masalahnya?
Abs
7
Untuk menguji hal-hal seperti itu tambahkan saja echosebelum perintah dan lihat apa fungsinya.
Marian
2
@ Maria, echosangat tidak bisa diandalkan - Anda tidak bisa membedakan antara echo "one argument"dan echo one argument(output yang terakhir menjadi salah, karena sebenarnya melewati echodua argumen yang sepenuhnya terpisah). Jauh lebih baik untuk melakukan sesuatu seperti -exec bash -c 'printf "%q " "$@"' _ ffmpeg -i {} -sameq {}.mp3 \; -printf '\n', yang akan mencetak keluaran dengan cara yang membuat karakter yang tidak dapat dicetak terlihat sehingga Anda dapat mendeteksi baris baru DOS dan keanehan lainnya.
Charles Duffy
52

Coba beri spasi sebelum masing-masing \;

Bekerja:

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

Tidak bekerja:

find . -name "*.log" -exec echo {}\;
Dustin Cowles
sumber
1
Ini sering membuatku tersandung. Suatu hari, saya akan menambahkan spasi secara default.
harperville
Bagi saya itu berfungsi sebaliknya di Cygwin di Windows 7: tidak ada ruang sebelumnya \; bekerja, dengan ruang - tidak. Tetapi jika saya menghapus \, dengan spasi sebelumnya; itu bekerja, dan tanpa ruang sebelumnya; tidak, seperti yang dijelaskan di sini.
WebComer
7

Sekadar informasi Anda:
Saya baru saja mencoba menggunakan perintah "find -exec" pada sistem Cygwin (UNIX diemulasikan pada Windows), dan tampaknya backslash sebelum tanda titik koma harus dihapus:
find ./ -name "blabla" -exec wc -l {} ;

Dominique
sumber
Saya sangat bingung. find /etc/nginx -name '*.conf' -exec echo {} ;dan find /etc/nginx -name '*.conf' -exec echo {}\;memberikan hasil yang sama. :(
Kirby
Saya menjalankan shell Bash yang datang dengan Git untuk Windows, dan jawaban Dustin Cowles cocok untuk saya. Dengan kata lain: tanpa tanda kutip, backslash lolos dengan tanda titik koma, spasi sesudahnya {}.
mamacdon
Tidak ada perbedaan dalam arti, tetapi dalam beberapa kasus Anda harus meletakkan backslash, dalam beberapa kasus Anda tidak dapat memasukkannya, dan dalam kasus lain lagi Anda mungkin memilih.
Dominique
2

Untuk berjaga-jaga kalau-kalau ada yang melihat "argumen -exec yang hilang" di skrip bash Amazon Opsworks Chef, saya perlu menambahkan backslash lain untuk keluar dari \;

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

Juga, jika ada orang lain yang memiliki "find: missing argumen to -exec" ini mungkin membantu:

Dalam beberapa shell Anda tidak perlu melakukan pelolosan, yaitu Anda tidak memerlukan "\" di depan ";".

find <file path> -name "myFile.*" -exec rm - f {} ;
penjual
sumber
2
Tidak ;dikutip atau melarikan diri di sini berarti dapat dikonsumsi oleh shell, tidak dibaca oleh find. Juga, -fdan - fada dua hal yang berbeda.
Charles Duffy
1

Anda perlu melakukan beberapa pelarian saya pikir.

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

{} Dan && akan menyebabkan masalah karena diperluas oleh baris perintah. Saya sarankan mencoba:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i \{} -sameq \{}.mp3 \; -exec rm \{} \;
VeeArr
sumber
Jika perintah pertama di exec berhasil dan perintah kedua di exec dieksekusi, apakah masih memiliki akses ke {}variabel untuk menghapus file yang tepat?
Abs
Untuk apa Anda {}mengembangkan thinik ? Kecuali itu mengandung dua titik atau koma yang akan tetap seperti itu.
Marian
0

Anda harus memberi jarak antara {}dan\;

Jadi perintahnya akan seperti:

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

Jika Anda masih mendapatkan "find: missing argumen to -exec" coba balas argumen eksekusi dengan tanda kutip.

find <file path> -type f -exec "chmod 664 {} \;"
merayu
sumber