find: argumen yang hilang ke -exec


18

Saya mencoba menjalankan perintah berikut:

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

Ini mengembalikan kesalahan:

find: missing argument to -exec

Saya tidak dapat melihat apa yang salah dengan perintah ini, karena sepertinya cocok dengan halaman manual:

perintah -exec {} +

Varian opsi -exec ini menjalankan perintah yang ditentukan pada file yang dipilih, tetapi baris perintah dibangun dengan menambahkan setiap nama file yang dipilih di akhir; jumlah undangan perintah akan jauh lebih sedikit daripada jumlah file yang cocok. Baris perintah dibangun dengan cara yang sama seperti xargs membangun baris perintahnya. Hanya satu instance dari '{}' diizinkan dalam perintah. Perintah dijalankan di direktori awal.

Saya juga mencoba:

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 '{}' \+

Sudahkah Anda mencoba melarikan diri +pada akhirnya? find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
jayhendren

3
Anda mungkin menggunakan GNU versi lama find. Meskipun -exec cmd {} +variannya adalah POSIX dan telah tersedia sejak tahun 80-an, GNU menemukan hanya menambahkannya (relatif) baru-baru ini (2005). Apa yang find --versionmemberitahu Anda?
Stéphane Chazelas

2
@Koveras, itu saja kalau begitu. -exec {} +ditambahkan pada 4.2.12 pada 2005. Dalam penemuan GNU yang lebih lama, Anda dapat menggunakan (non-POSIX) -print0 | xargs -r0untuk mendapatkan yang serupa. 4.1berasal dari 1994.
Stéphane Chazelas

1
JRFerguson menunjukkan (di jawaban yang telah dihapus) bahwa -nameargumen pola harus dikutip: -name "*.c" -o -name "*.h". Ini benar, meskipun itu tidak terkait dengan -execkesalahan. Anda akan melihat bahwa semua jawaban lain memasukkan tanda kutip ke dalam tanda kutip, meskipun hanya Gilles yang menyebutkannya. … (Lanjutan)
G-Man Mengatakan 'Reinstate Monica'

1
(Lanjutan) ... jawaban jlliagre meruntuhkan ekspresi nama menjadi -name "*.[ch]"tanpa penjelasan. Ini memiliki manfaat menyederhanakan baris perintah dan, khususnya, menghilangkan  -o. Menemukan ekspresi yang melibatkan -osulit untuk diperbaiki. Anda salah; jika perintah Anda diperbaiki sehingga tidak salah (seperti dalam jawaban Gilles), itu grephanya akan berjalan pada .hfile. Yang perlu Anda lakukan '(' -name '*.c' -o -name '*.h' ')'.
G-Man Mengatakan 'Reinstate Monica'

Jawaban:


18

Anda perlu menghapus tanda kutip tunggal yang Anda gunakan di sekitar {}. Perintah dapat disederhanakan seperti ini:

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

Jika Anda menggunakan versi menemukan GNU kuno, ini harus tetap berfungsi:

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

Ups, itu dimaksudkan sebagai kutipan, bukan backtick.
David Kennedy

Kutipan akan sia-sia karena {}tidak memiliki arti khusus untuk shell.
jlliagre

Dari halaman manual find: "String '{}' diganti dengan nama file saat ini sedang diproses di mana-mana itu terjadi dalam argumen ke perintah, bukan hanya dalam argumen di mana itu sendirian, seperti dalam beberapa versi find. Keduanya konstruksi mungkin perlu diloloskan (dengan '\') atau dikutip untuk melindunginya dari ekspansi oleh shell. "
David Kennedy

1
Saya memang membacanya di halaman manual tetapi faktanya tidak ada cangkang yang saya sadari yang mengharuskan mengutip kurung kurawal. Shell apa yang Anda gunakan?
jlliagre

pesta. Dengan atau tanpa tanda kutip saya mendapatkan kesalahan.
David Kennedy

10

"Argumen yang hilang -exec" biasanya berarti bahwa argumen untuk - exectidak ada terminatornya. Terminator harus berupa argumen yang hanya berisi karakter ;(yang perlu dikutip dalam perintah shell, jadi biasanya ditulis \;atau ';'), atau dua argumen berturut-turut yang mengandung {}dan +.

Stephane Chazelas telah mengidentifikasi bahwa Anda menggunakan versi GNU yang lebih lama yang tidak -exec … {} +hanya mendukung -exec {} \;. Meskipun GNU adalah pengadopsi akhir -exec … {} +, saya merekomendasikan Anda untuk mendapatkan tool suite yang kurang antik (seperti Cygwin , yang mencakup git dan banyak lagi, atau GNUwin32 , yang tidak memiliki git tetapi tidak memiliki karyawan yang mencoba-buruk -untuk menggunakan-linux-but-we-impose-windows vibe yang diberikan Cygwin). Fitur ini ditambahkan dalam versi 4.2.12, lebih dari 9 tahun yang lalu (itu adalah fitur terakhir yang diidentifikasi untuk membuat GNU findPOSIX-compliant).

Jika Anda ingin tetap menggunakan GNU yang lebih lama, Anda dapat menggunakannya -print0dengan xargs -0untuk mendapatkan fungsionalitas yang serupa: eksekusi perintah yang dikelompokkan, mendukung nama file yang sewenang-wenang.

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

Selalu kutip wildcard di findbaris perintah. Jika tidak, jika Anda menjalankan perintah ini dari direktori yang berisi .cfile, tanda kutip *.cakan diperluas ke daftar .cfile di direktori saat ini.

Menambahkan /dev/nullke grepbaris perintah adalah trik untuk memastikan bahwa grep akan selalu mencetak nama file, bahkan jika findkebetulan menemukan kecocokan tunggal. Dengan GNU find, metode lain adalah dengan melewatkan opsi -H.


1
Apa yang Anda maksud dengan getaran buruk windows-karyawan-mencoba-menggunakan-linux-tapi-kami-memaksakan-yang memberikan cygwin?
David Kennedy

GNUwin32 tidak mengharapkan :(
David Kennedy

Lihat komentar saya pada pertanyaan.
G-Man Mengatakan 'Reinstate Monica'

Kutipan di sekitar semi bekerja dari dalam script package.json.
bvj

2

Jika perintah seperti

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

mengembalikan kesalahan

find: missing argument to -exec

kemungkinan penyebabnya adalah GNU findyang terlalu lama yang tidak mendukung sintaksis -exec mycommand {} +. Dalam hal ini penggantian kinerja rendah adalah menjalankan -exec mycommand {} \;yang akan berjalan mycommandsekali untuk setiap target yang ditemukan alih-alih mengumpulkan beberapa target dan menjalankan mycommandhanya sekali.

Namun, GNU findtidak mendukung misalnya

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

karena GNU findhanya mendukung kombinasi literal {} +alih-alih lebih umum {} additional parameters +. Perhatikan bahwa tidak mungkin ada apa pun antara kawat gigi dan +karakter. Jika Anda mencoba ini, Anda akan mendapatkan kesalahan yang sama:

find: missing argument to -exec

Solusinya adalah menggunakan sintaks {} additional parameters \;yang berfungsi tetapi akan menjalankan perintah sekali untuk setiap target yang ditemukan. Jika Anda membutuhkan lebih banyak kinerja dengan GNU findAnda harus menulis skrip wrapper yang dapat menambahkan parameter tambahan ke argumen yang diberikan. Sesuatu seperti

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

harus cukup baik. Atau, jika Anda tidak ingin membuat file sementara, Anda dapat menggunakan satu-baris untuk mengubah urutan parameter seperti ini:

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

yang akan dieksekusi mycommand {list of ttf files} extra arguments. Perhatikan bahwa Anda mungkin perlu menggandakan karakter khusus untuk bash setelah -cbendera.


(1) Bagian di atas yang benar-benar menjawab pertanyaan sudah diberikan oleh orang lain. (2) Apa yang Anda gambarkan bukanlah cacat atau kekurangan dalam GNU find, tetapi perilaku yang benar yang ditentukan oleh POSIX .
G-Man Mengatakan 'Reinstate Monica'

1
+1 Akhirnya, seseorang yang menjawab mengapa parameter tambahan tidak berfungsi! Sepertinya kekurangan dalam definisi POSIX.
Jonathan

Jika Anda memiliki GNU, findAnda mungkin memiliki GNU cp. Dalam hal ini Anda bisa find ... -exec cp --target-directory ~/.fonts {} +menyimpan {}di akhir string eksekusi.
roaima

1

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

mendapat kesalahan find: missing argument to ``-exec'.

Menambahkan ruang di antara {}dan \memperbaikinya:

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


1
Tidak ada masalah seperti itu dalam findperintah di pertanyaan yang dihadapi.
Kusalananda

Dalam Pertanyaan itu tidak, baik, yang saya mengerti, tetapi masalahnya sama "find: missing argumen to` `-exec '", Masalah dapat terjadi dari alasan-2 yang berbeda, saya menjawab karena saya melihat pernyataan masalah yang sama.
ShreePool

@Kusalananda kesedihan yang baik, noob memberikan solusi untuk kesalahan yang dilaporkan yang dinyatakan oleh OP dalam judul dan isi pertanyaan.
bvj

@ bvj Pertanyaan secara eksplisit berkaitan dengan +bentuk -execopsi untuk find. Jawaban ini memperbaiki masalah yang tidak dimiliki pengguna yang mengajukan pertanyaan.
Kusalananda

-1

Saya mengalami sakit kepala dengan sintaks exec di masa lalu. hampir setiap hari saya lebih suka sintaks bash yang lebih bagus:

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

Ini memiliki beberapa keterbatasan ketika Anda ingin memperlakukan file sebagai grup, karena masing-masing dievaluasi secara seri, tetapi Anda dapat menyalurkan output di tempat lain dengan baik


1
Meskipun ini cenderung berfungsi tetapi secara signifikan kurang berguna daripada versi pure-find karena tidak dapat menangani file dengan spasi putih dalam nama dengan benar.
Etan Reisner

5
Tidak, jangan lakukan ini. Ini pecah segera setelah file berisi spasi dan karakter "aneh" lainnya. Ini juga lebih kompleks dan lebih lambat daripada find … -exec … \;, jadi tidak ada alasan untuk menggunakan ini bahkan jika Anda tahu bahwa nama file Anda jinak.
Gilles 'SANGAT berhenti menjadi jahat'

ini sangat membantu untuk situasi saya di mana saya perlu menjalankan beberapa baris logika berdasarkan nama file (seperti menghapus karakter, membuat direktori dan kemudian memindahkan file). Mencoba menemukan melakukan banyak hal dalam satu execadalah terlalu banyak sakit kepala selama 5 menit yang ingin saya habiskan untuk ini. Nama file saya jinak dan ini menyelesaikan masalah saya :)
gMale
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.