Apakah ada cara untuk find
menjalankan fungsi yang saya definisikan di shell? Sebagai contoh:
dosomething () {
echo "doing something with $1"
}
find . -exec dosomething {} \;
Hasilnya adalah:
find: dosomething: No such file or directory
Apakah ada cara untuk mendapatkan find
's -exec
untuk melihat dosomething
?
$0
.find . -exec bash -c 'dosomething "$0"' {} \;
akan menangani spasi (dan karakter aneh lainnya) dalam nama file ...export -f
hanya akan berfungsi di beberapa versi bash. Itu bukan posix, bukan crossplatforn,/bin/sh
akan memiliki kesalahan dengan itusumber
while read
for for loop;for item in $(find . ); do some_function "${item}"; done
Jawaban Jak di atas bagus tetapi memiliki beberapa jebakan yang mudah diatasi:
Ini menggunakan null sebagai pembatas alih-alih umpan baris, sehingga nama file dengan umpan baris akan berfungsi. Itu juga menggunakan
-r
bendera yang menonaktifkan backslash melarikan diri, tanpa itu backslash dalam nama file tidak akan berfungsi. Itu juga membersihkanIFS
sehingga potensi spasi putih tertinggal dalam nama tidak dibuang.sumber
/bin/bash
tetapi tidak akan bekerja/bin/sh
. Sayang sekali.Tambahkan kutipan
{}
seperti yang ditunjukkan di bawah ini:Ini memperbaiki kesalahan apa pun karena karakter khusus dikembalikan oleh
find
, misalnya file dengan tanda kurung dalam namanya.sumber
{}
. Ini akan mematahkan untuk nama file yang berisi tanda kutip ganda.touch '"; rm -rf .; echo "I deleted all you files, haha
. Ups.-exec bash -c 'echo $0' '{}' \;
Perhatikan bahwa ketika menggunakanbash -c
, $ 0 adalah argumen pertama, bukan nama skrip.Memproses hasil dalam jumlah besar
Untuk meningkatkan efisiensi, banyak orang menggunakan
xargs
untuk memproses hasil dalam jumlah besar, tetapi sangat berbahaya. Karena itu ada metode alternatif yang diperkenalkan ke dalam melakukanfind
hasil dalam jumlah besar.Catat bahwa metode ini mungkin datang dengan beberapa peringatan seperti misalnya persyaratan dalam POSIX-
find
harus ada{}
di akhir perintah.find
akan melewatkan banyak hasil sebagai argumen untuk satu panggilan tunggalbash
danfor
-loop mengulangi argumen tersebut, menjalankan fungsidosomething
pada masing-masing argumen tersebut.Solusi di atas memulai argumen di
$1
, itulah sebabnya ada_
(yang mewakili$0
).Memproses hasil satu per satu
Dengan cara yang sama, saya berpikir bahwa jawaban teratas yang diterima harus diperbaiki
Ini tidak hanya lebih waras, karena argumen harus selalu dimulai
$1
, tetapi juga menggunakan$0
dapat menyebabkan perilaku yang tidak terduga jika nama file dikembalikan denganfind
memiliki arti khusus pada shell.sumber
Buat skrip memanggil dirinya sendiri, melewati setiap item yang ditemukan sebagai argumen:
Saat Anda menjalankan skrip dengan sendirinya, ia menemukan apa yang Anda cari dan menyebut dirinya melewati setiap hasil temuan sebagai argumen. Ketika skrip dijalankan dengan argumen, ia menjalankan perintah pada argumen dan kemudian keluar.
sumber
find: ‘myscript.sh’: No such file or directory
jika dimulai sebagaibash myscript.sh
...Bagi Anda yang mencari fungsi bash yang akan menjalankan perintah yang diberikan pada semua file di direktori saat ini, saya telah mengkompilasi salah satu dari jawaban di atas:
Perhatikan bahwa itu rusak dengan nama file yang berisi spasi (lihat di bawah).
Sebagai contoh, ambil fungsi ini:
Katakanlah saya ingin mengubah semua instance hello ke dunia dalam semua file di direktori saat ini. Saya akan lakukan:
Agar aman dengan simbol apa pun dalam nama file, gunakan:
(tetapi Anda membutuhkan
find
yang menangani-print0
misalnya, GNUfind
).sumber
Saya menemukan cara termudah sebagai berikut, mengulangi dua perintah dalam satu do
sumber
Untuk referensi, saya menghindari skenario ini menggunakan:
Dapatkan Output dari find di file skrip saat ini dan beralih ke output sesuai keinginan Anda. Saya setuju dengan jawaban yang diterima, tetapi saya tidak ingin mengekspos fungsi di luar file skrip saya.
sumber
Tidak mungkin menjalankan fungsi seperti itu.
Untuk mengatasinya, Anda dapat menempatkan fungsi Anda dalam skrip shell dan memanggilnya dari
find
Sekarang gunakan di find sebagai:
sumber
dosomething $1
=>dosomething "$1"
dan mulai file Anda dengan benar denganfind . -exec bash dosomething.sh {} \;
Masukkan fungsi dalam file terpisah dan
find
jalankan untuk itu.Fungsi-fungsi Shell bersifat internal ke shell-nya;
find
tidak akan pernah bisa melihat mereka.sumber
Untuk memberikan tambahan dan klarifikasi pada beberapa jawaban lain, jika Anda menggunakan opsi massal untuk
exec
atauexecdir
(-exec command {} +
), dan ingin mengambil semua argumen posisi, Anda perlu mempertimbangkan penanganan$0
denganbash -c
. Lebih konkret, pertimbangkan perintah di bawah ini, yang digunakanbash -c
seperti yang disarankan di atas, dan cukup gema jalur file yang diakhiri dengan '.wav' dari setiap direktori yang ditemukannya:Manual bash mengatakan:
Di sini,
'check $@'
adalah string perintah, dan_ {}
argumen setelah string perintah. Perhatikan bahwa$@
adalah parameter posisi khusus dalam bash yang diperluas ke semua parameter posisi mulai dari 1 . Perhatikan juga bahwa dengan-c
opsi, argumen pertama ditugaskan ke parameter posisi$0
. Ini berarti bahwa jika Anda mencoba mengakses semua parameter posisi dengan$@
, Anda hanya akan mendapatkan parameter mulai dari$1
dan ke atas. Itulah alasan mengapa jawaban Dominik memiliki_
, yang merupakan argumen dummy untuk mengisi parameter$0
, jadi semua argumen yang kita inginkan tersedia nanti jika kita menggunakan$@
ekspansi parameter misalnya, atau untuk loop seperti dalam jawaban itu.Tentu saja, mirip dengan jawaban yang diterima,
bash -c 'shell_function $0 $@'
juga akan bekerja dengan melewati secara eksplisit$0
, tetapi sekali lagi, Anda harus ingat bahwa$@
itu tidak akan berfungsi seperti yang diharapkan.sumber
Tidak secara langsung, tidak. Find dijalankan dalam proses terpisah, bukan di shell Anda.
Buat skrip shell yang melakukan pekerjaan yang sama dengan fungsi Anda dan temukan
-exec
itu.sumber
Saya akan menghindari menggunakan
-exec
semuanya. Kenapa tidak digunakanxargs
?sumber