Saya menggunakan Solaris 10 dan saya telah menguji yang berikut dengan ksh (88), bash (3.00) dan zsh (4.2.1).
Kode berikut tidak menghasilkan hasil apa pun:
function foo {
echo "Hello World"
}
find somedir -exec foo \;
Temuan tidak cocok dengan beberapa file (seperti yang ditunjukkan dengan mengganti -exec ...
dengan -print
), dan fungsinya berfungsi dengan baik ketika dipanggil di luar dari find
panggilan.
Inilah yang dikatakan man find
laman tentang -exec
:
-exec command Benar jika perintah yang dijalankan mengembalikan a nilai nol sebagai status keluar. Akhir dari perintah harus diselingi oleh yang melarikan diri titik koma (;). Argumen perintah {} adalah diganti dengan pathname saat ini. Jika argumen terakhir ke -exec adalah {} dan Anda tentukan + daripada tanda titik koma (;), perintah dipanggil lebih sedikit, dengan {} digantikan oleh grup nama path. Jika setiap pemanggilan perintah mengembalikan a nilai bukan nol sebagai status keluar, temukan mengembalikan status keluar bukan nol.
Saya mungkin bisa melakukan sesuatu seperti ini:
for f in $(find somedir); do
foo
done
Tapi saya takut berurusan dengan masalah pemisah lapangan.
Apakah mungkin untuk memanggil fungsi shell (didefinisikan dalam skrip yang sama, jangan repot-repot dengan masalah pelingkupan) dari find ... -exec ...
panggilan?
Saya mencobanya dengan keduanya /usr/bin/find
dan /bin/find
dan mendapatkan hasil yang sama.
export -f foo
PATH
. Atau, gunakansh -c '...'
dan keduanya mendefinisikan DAN menjalankan fungsi dalam...
bit. Mungkin membantu untuk memahami perbedaan antara fungsi dan skrip .Jawaban:
A
function
adalah lokal untuk sebuah shell, jadi Anda perlufind -exec
memunculkan shell dan memiliki fungsi yang didefinisikan dalam shell itu sebelum dapat menggunakannya. Sesuatu seperti:bash
memungkinkan seseorang untuk mengekspor fungsi melalui lingkungan denganexport -f
, sehingga Anda dapat melakukan (dalam bash):ksh88
harustypeset -fx
mengekspor fungsi (bukan melalui lingkungan), tetapi itu hanya dapat digunakan oleh she-bang lebih sedikit skrip yang dieksekusi olehksh
, jadi tidak denganksh -c
.Pilihan lain adalah melakukan:
Artinya, gunakan
typeset -f
untuk membuang definisifoo
fungsi di dalam skrip inline. Perhatikan bahwa jikafoo
menggunakan fungsi lain, Anda juga harus membuangnya juga.sumber
ksh
ataubash
dalam-exec
perintah? Saya mengerti yang pertama, tetapi bukan yang kedua.bash -c 'some-code' a b c
,$0
isa
,$1
isb
..., jadi jika Anda ingin$@
menjadia, b, c
Anda harus memasukkan sesuatu sebelumnya. Karena$0
juga digunakan saat menampilkan pesan kesalahan, itu ide yang baik untuk menggunakan nama shell, atau sesuatu yang masuk akal dalam konteks itu.Ini tidak selalu berlaku, tetapi ketika itu, itu adalah solusi sederhana. Setel
globstar
opsi (set -o globstar
dalam ksh93,shopt -s globstar
dalam bash ≥4 ; aktif secara default di zsh). Lalu gunakan**/
untuk mencocokkan direktori saat ini dan subdirektori secara rekursif.Misalnya, alih-alih
find . -name '*.txt' -exec somecommand {} \;
, Anda dapat menjalankanAlih-alih
find . -type d -exec somecommand {} \;
, Anda bisa lariAlih-alih
find . -newer somefile -exec somecommand {} \;
, Anda bisa lariKetika
**/
tidak bekerja untuk Anda (karena shell Anda tidak memilikinya, atau karena Anda memerlukanfind
opsi yang tidak memiliki analog shell), tentukan fungsi dalamfind -exec
argumen .sumber
globstar
opsi pada versi ksh (ksh88
) yang saya gunakan.dtksh
(ksh93 dengan beberapa ekstensi X11), tetapi versi lama dan mungkin bagian dari paket opsional di mana CDE adalah opsional.find
karena tidak termasuk dotfiles dan tidak turun ke dotdir dan bahwa itu mengurutkan daftar file (keduanya dapat alamat di zsh melalui kualifikasi globbing). Juga dengan**/*
berlawanan dengan./**/*
, nama file dapat dimulai dengan-
.Gunakan \ 0 sebagai pembatas dan baca nama file ke proses saat ini dari perintah spawned, seperti:
Apa yang terjadi di sini:
read -d ''
membaca hingga byte \ 0 berikutnya, jadi Anda tidak perlu khawatir tentang karakter aneh dalam nama file.-print0
gunakan \ 0 untuk mengakhiri setiap nama file yang dihasilkan, bukan \ n.cmd2 < <(cmd1)
sama seperticmd1 | cmd2
kecuali bahwa cmd2 dijalankan di shell utama dan bukan subshell./dev/null
untuk memastikan tidak sengaja membaca dari pipa.$filename
dikutip sehingga shell tidak mencoba untuk membagi nama file yang berisi spasi putih.Sekarang,
read -d
dan<(...)
berada di zsh, bash dan ksh 93u, tapi saya tidak yakin tentang versi ksh sebelumnya.sumber
jika Anda ingin proses anak, dihasilkan dari skrip Anda, untuk menggunakan fungsi shell yang telah ditentukan sebelumnya Anda perlu mengekspornya
export -f <function>
CATATAN:
export -f
spesifik untuk bashkarena hanya shell yang dapat menjalankan fungsi shell :
EDIT: pada dasarnya skrip Anda harus menyerupai ini:
sumber
export -f
adalah kesalahan sintaksis dalamksh
, dan mencetak definisi fungsi ke layar padazsh
. Dalam semuaksh
,zsh
danbash
, itu tidak menyelesaikan masalah.find / -exec /bin/bash -c 'function' \;
bash
. Terima kasih!{}
kode shell! Itu berarti nama file ditafsirkan sebagai kode shell sehingga sangat berbahaya