Jawaban ini datang di bagian berikut:
- Penggunaan dasar
-exec
- Menggunakan
-execdalam kombinasi dengansh -c
- Menggunakan
-exec ... {} +
- Menggunakan
-execdir
Penggunaan dasar -exec
The -execpilihan mengambil utilitas eksternal dengan argumen opsional sebagai argumen dan mengeksekusi itu.
Jika string {}ada di mana saja dalam perintah yang diberikan, setiap instance akan digantikan oleh pathname yang saat ini sedang diproses (misalnya ./some/path/FILENAME). Dalam kebanyakan shell, kedua karakter {}tidak perlu dikutip.
Perintah perlu diakhiri dengan ;untuk findmengetahui di mana ia berakhir (karena mungkin ada opsi lebih lanjut setelah itu). Untuk melindungi ;shell, shell harus dikutip sebagai \;atau ';', jika tidak shell akan melihatnya sebagai akhir dari findperintah.
Contoh ( \pada akhir dua baris pertama hanya untuk kelanjutan baris):
find . -type f -name '*.txt' \
-exec grep -q 'hello' {} ';' \
-exec cat {} ';'
Ini akan menemukan semua file biasa ( -type f) yang namanya cocok dengan pola *.txtdi atau di bawah direktori saat ini. Kemudian akan menguji apakah string helloterjadi di salah satu file yang ditemukan menggunakan grep -q(yang tidak menghasilkan output apa pun, hanya status keluar). Untuk file-file yang berisi string, catakan dieksekusi untuk menampilkan isi file ke terminal.
Masing-masing -execjuga bertindak seperti "tes" pada nama path yang ditemukan oleh find, sama seperti -typedan -nametidak. Jika perintah mengembalikan status keluar nol (menandakan "sukses"), bagian selanjutnya dari findperintah dipertimbangkan, jika tidak, findperintah akan dilanjutkan dengan nama path berikutnya. Ini digunakan dalam contoh di atas untuk menemukan file yang berisi string hello, tetapi untuk mengabaikan semua file lainnya.
Contoh di atas menggambarkan dua kasus penggunaan paling umum -exec:
- Sebagai ujian untuk lebih membatasi pencarian.
- Untuk melakukan beberapa tindakan pada pathname yang ditemukan (biasanya, tetapi tidak harus, di akhir
findperintah).
Menggunakan -execdalam kombinasi dengansh -c
Perintah yang -execdapat dieksekusi terbatas pada utilitas eksternal dengan argumen opsional. Untuk menggunakan built-in shell, fungsi, kondisional, jalur pipa, pengalihan dll secara langsung dengan -exectidak dimungkinkan, kecuali dibungkus dengan sesuatu seperti sh -cshell anak.
Jika bashfitur diperlukan, maka gunakan bash -cdi tempat sh -c.
sh -cberjalan /bin/shdengan skrip yang diberikan pada baris perintah, diikuti oleh argumen baris perintah opsional untuk skrip itu.
Contoh sederhana penggunaannya sh -csendiri, tanpa find:
sh -c 'echo "You gave me $1, thanks!"' sh "apples"
Ini meneruskan dua argumen ke skrip shell anak:
String sh. Ini akan tersedia sebagai $0di dalam skrip, dan jika shell internal menampilkan pesan kesalahan, ia akan awalan dengan string ini.
Argumen applestersebut tersedia seperti $1dalam skrip, dan jika ada lebih banyak argumen, maka ini akan tersedia sebagai $2, $3dll. Mereka juga akan tersedia dalam daftar "$@"(kecuali $0yang tidak akan menjadi bagian dari "$@").
Ini berguna dalam kombinasi dengan -execkarena memungkinkan kita untuk membuat skrip kompleks yang bertindak sewenang-wenang pada nama path yang ditemukan oleh find.
Contoh: Temukan semua file biasa yang memiliki akhiran nama file tertentu, dan ubah akhiran nama file itu ke beberapa akhiran lainnya, di mana akhiran disimpan dalam variabel:
from=text # Find files that have names like something.text
to=txt # Change the .text suffix to .txt
find . -type f -name "*.$from" -exec sh -c 'mv "$3" "${3%.$1}.$2"' sh "$from" "$to" {} ';'
Di dalam skrip internal, $1akan menjadi string text, $2akan menjadi string txtdan $3akan menjadi apa pun pathname yang findditemukan untuk kita. Ekspansi parameter ${3%.$1}akan mengambil pathname dan menghapus akhiran .textdarinya.
Atau, menggunakan dirname/ basename:
find . -type f -name "*.$from" -exec sh -c '
mv "$3" "$(dirname "$3")/$(basename "$3" ".$1").$2"' sh "$from" "$to" {} ';'
atau, dengan variabel yang ditambahkan di skrip internal:
find . -type f -name "*.$from" -exec sh -c '
from=$1; to=$2; pathname=$3
mv "$pathname" "$(dirname "$pathname")/$(basename "$pathname" ".$from").$to"' sh "$from" "$to" {} ';'
Perhatikan bahwa dalam variasi terakhir ini, variabel fromdan todi shell anak berbeda dari variabel dengan nama yang sama di skrip eksternal.
Di atas adalah cara yang benar memanggil script kompleks sewenang-wenang dari -execdengan find. Menggunakan finddalam lingkaran seperti
for pathname in $( find ... ); do
rentan terhadap kesalahan dan tidak tangguh (pendapat pribadi). Ini adalah pemisahan nama file pada spasi putih, memanggil globbing nama file, dan juga memaksa shell untuk memperluas hasil lengkap findsebelum bahkan menjalankan iterasi pertama dari loop.
Lihat juga:
Menggunakan -exec ... {} +
Pada ;akhirnya dapat diganti dengan +. Ini menyebabkan finduntuk mengeksekusi perintah yang diberikan dengan sebanyak mungkin argumen (ditemukan nama path) daripada satu untuk setiap nama path yang ditemukan. String {} harus terjadi tepat sebelum +ini berfungsi .
find . -type f -name '*.txt' \
-exec grep -q 'hello' {} ';' \
-exec cat {} +
Di sini, findakan mengumpulkan nama path yang dihasilkan dan mengeksekusi catpada sebanyak mungkin dari mereka sekaligus.
find . -type f -name "*.txt" \
-exec grep -q "hello" {} ';' \
-exec mv -t /tmp/files_with_hello/ {} +
Demikian juga di sini, mvakan dieksekusi beberapa kali mungkin. Contoh terakhir ini membutuhkan GNU mvdari coreutils (yang mendukung -topsi).
Menggunakan -exec sh -c ... {} +juga merupakan cara yang efisien untuk mengulang set nama path dengan skrip yang sewenang-wenang.
Dasar-dasarnya sama dengan ketika menggunakan -exec sh -c ... {} ';', tetapi skrip sekarang membutuhkan daftar argumen yang jauh lebih lama. Ini dapat diulang dengan mengulang "$@"di dalam skrip.
Contoh kami dari bagian terakhir yang mengubah akhiran nama file:
from=text # Find files that have names like something.text
to=txt # Change the .text suffix to .txt
find . -type f -name "*.$from" -exec sh -c '
from=$1; to=$2
shift 2 # remove the first two arguments from the list
# because in this case these are *not* pathnames
# given to us by find
for pathname do # or: for pathname in "$@"; do
mv "$pathname" "${pathname%.$from}.$to"
done' sh "$from" "$to" {} +
Menggunakan -execdir
Ada juga -execdir(diimplementasikan oleh sebagian besar findvarian, tetapi bukan opsi standar).
Ini berfungsi seperti -execdengan perbedaan bahwa perintah shell yang diberikan dieksekusi dengan direktori pathname yang ditemukan sebagai direktori kerjanya saat ini dan itu {}akan berisi nama samaran dari pathname yang ditemukan tanpa pathnya (tetapi GNU findmasih akan awalan dengan nama basenya ./, sementara BSD findtidak akan melakukan itu).
Contoh:
find . -type f -name '*.txt' \
-execdir mv {} done-texts/{}.done \;
Ini akan memindahkan setiap *.txtfile -file yang ditemukan ke done-textssubdirektori yang sudah ada di direktori yang sama dengan tempat file ditemukan . File juga akan diganti namanya dengan menambahkan akhiran .doneke dalamnya.
Ini akan sedikit lebih sulit untuk dilakukan -execkarena kita harus mengeluarkan nama file dari file yang ditemukan {}untuk membentuk nama file yang baru. Kami juga memerlukan nama direktori dari {}untuk menemukan done-textsdirektori dengan benar.
Dengan -execdir, beberapa hal seperti ini menjadi lebih mudah.
Operasi yang sesuai menggunakan -execalih-alih -execdirharus menggunakan shell anak:
find . -type f -name '*.txt' -exec sh -c '
for name do
mv "$name" "$( dirname "$name" )/done-texts/$( basename "$name" ).done"
done' sh {} +
atau,
find . -type f -name '*.txt' -exec sh -c '
for name do
mv "$name" "${name%/*}/done-texts/${name##*/}.done"
done' sh {} +