Bagaimana cara ini menemukan perintah menggunakan "find ... -exec sh -c '...' sh {} +" berfungsi?

8

@StephaneChazelas memposting solusi berikut untuk T&J ini: Mengalami masalah menggunakan “find -exec {} +” .

$ find . -iname "*.extension" -exec sh -c '
  exec <command> "$@" <additional parameters>' sh {} +

Apa sebenarnya yang terjadi di sini? Secara spesifik apa yang terakhir sh {}dilakukan? Sepertinya itu hanya ada untuk menenangkan -execperintah find sehingga ada sesuatu yang harus dilakukan, sebuah NOOP.

Saya bisa dengan mudah meletakkannya di echo {}sana dan tampaknya berfungsi dengan baik.

slm
sumber

Jawaban:

9

Sintaksnya adalah:

find ... -exec cmd {} +

findakan menemukan sejumlah file berdasarkan kriteria di ...dan dijalankan cmddengan daftar jalur file sebagai argumen, sebanyak mungkin tanpa melampaui batas pada ukuran argumen ke perintah.

Jika perlu dapat membagi daftar file dan memanggil cmdbeberapa kali. Misalnya, ini mungkin berakhir dengan panggilan:

cmd ./file1 ./file2 ... ./file3000
cmd ./file3001 ./file3002 ... ./file4321

Keterbatasan dengan itu adalah yang {}terakhir. Misalnya, Anda tidak dapat menulis:

find ... -exec cmd {} other args +

seperti yang Anda bisa dengan ';'bukan '+'.

Kamu bisa menulis:

find ... -exec echo foo {} +

tapi tidak:

find ... -exec echo {} foo +

Jadi, jika Anda perlu menambahkan beberapa argumen tambahan cmdsetelah daftar file, Anda harus menggunakan shell. (Alasan lain mengapa Anda perlu memanggil shell adalah kapan saja Anda perlu menggunakan fitur shell seperti pengalihan, pipa, beberapa ekspansi string ....)

Dalam sh -c 'inline-script' x a b c, untuk inline-script, $0adalah x, $1adalah a, $2adalah b... demikian "$@"juga daftar 3 argumen: a, b dan c. Jadi di:

find ... -exec sh -c 'cmd "$@" other arg' find-sh {} +

Untuk skrip inline , $0(yang digunakan misalnya saat menampilkan pesan kesalahan) diatur ke find-shdan "$@"merupakan daftar file (apa yang finddiperluas {}ke).

Dengan menggunakan execbuiltin khusus dari shell:

find ... -exec sh -c 'exec cmd "$@" other arg' find-sh {} +

Kami memberi tahu shell untuk tidak melakukan proses tambahan untuk menjalankan cmd, tetapi sebaliknya menjalankannya dalam proses yang sama (mengganti proses shell yang berjalan dengan perintah itu). Beberapa shell suka bash, zshdan beberapa implementasi kshmelakukannya secara implisit untuk perintah terakhir dalam sebuah skrip.

Stéphane Chazelas
sumber
Bisakah Anda menggunakan subkulit alih-alih exec di sana? -exec sh -c '(cmd1; cmd2;)' find-sh {} +?
slm
Jadi jika saya mengerti Anda dengan benar, find-sh {}argumen apa yang ada pada perintah sh -c '...', kan?
slm
@slm, findakan memanggil /bin/shdengan sebagai argumen ("sh", "-c", "...", "find-sh", "./file1", "./file2"...). And inside ... , that maps (the shells maps that) to $ 0` makhluk "find-sh", dan parameter posisi ( $1, $2... yang bisa dibilang adalah argumen untuk naskah inline ) menjadi ./file1, ./file2.
Stéphane Chazelas