Bu cevap aşağıdaki bölümlerde gelir:
- Temel kullanımı
-exec
-execİle birlikte kullanmaksh -c
- kullanma
-exec ... {} +
- kullanma
-execdir
Temel kullanımı -exec
-execSeçenek, bağımsız değişken olarak isteğe bağlı argümanlar bir dış yardımcı alır ve çalıştırır.
Dize {}verilen komutun herhangi bir yerinde mevcutsa, onun her bir örneği o anda işlenmekte olan yol adıyla değiştirilecektir (örn. ./some/path/FILENAME). Çoğu kabukta, iki karakterin {}alıntılanması gerekmez.
Komutun nerede bittiğini bilmek ;için bir for ile sonlandırılması findgerekir (daha sonra başka seçenekler de olabilir). Kabuktan korunmak için ;, \;veya olarak belirtilmesi gerekir ';', aksi takdirde kabuk findkomutun sonu olarak görür .
Örnek ( \ilk iki satırın sonunda sadece satır devam ediyor):
find . -type f -name '*.txt' \
-exec grep -q 'hello' {} ';' \
-exec cat {} ';'
Bu -type f, isimleri *.txtgeçerli dizindeki veya altındaki desene uyan tüm normal dosyaları ( ) bulacaktır . Daha sonra dizenin hellokullanarak bulunan herhangi bir dosyada ortaya çıkıp çıkmadığını test eder grep -q(herhangi bir çıktı üretmez, sadece bir çıkış durumu). Dizeyi içeren dosyalar catiçin dosyanın içeriğini terminale vermek için çalıştırılır.
Her biri , tıpkı olduğu gibi ve yaptığı -execyollarda bir "test" gibi davranır . Komut sıfır bir çıkış durumu verirse ("başarı" anlamına gelir), komutun bir sonraki kısmı dikkate alınır, aksi halde komut bir sonraki yol adı ile devam eder. Bu, yukarıdaki örnekte, dizeyi içeren dosyaları bulmak , ancak diğer tüm dosyaları yoksaymak için kullanılır.find-type-namefindfindhello
Yukarıdaki örnekte, en yaygın kullanılan iki kullanım örneği gösterilmektedir -exec:
- Aramayı daha da kısıtlamak için bir test olarak.
- Bulunan yol adı üzerinde bir tür eylem gerçekleştirmek için (genellikle, ancak
findkomutun sonunda gerekli değildir ).
-execİle birlikte kullanmaksh -c
Yürütülebilir komut -execisteğe bağlı değişkenlerle birlikte harici bir yardımcı programla sınırlıdır. Kabuk yapılarını, fonksiyonlarını, koşullarını, boru hatlarını, yönlendirmeleri vb. -execKullanarak bir sh -cçocuk kabuğu gibi bir şey içine sarılmadıkça doğrudan kullanmak mümkün değildir .
Eğer bashözellikler gerekliyse, bash -cyerine kullanın sh -c.
sh -c/bin/shkomut satırında verilen bir komut dosyasıyla çalışır , ardından bu komut dosyasına isteğe bağlı komut satırı argümanları uygulanır.
Kullanmadan sh -ckendi başına kullanmanın basit bir örneği find:
sh -c 'echo "You gave me $1, thanks!"' sh "apples"
Bu, alt kabuk betiğine iki argüman iletir:
Dize sh. Bu $0, betiğin içinde olduğu gibi mevcut olacak ve eğer iç kabuk bir hata mesajı veriyorsa, onu bu dizeyle ön ekleyecektir.
Argüman senaryodaki applesgibi mevcuttur $1ve daha fazla argüman olsaydı, o zaman bunlar şu gibi mevcut olurdu $2, $3vs. Listede de mevcut olurdu "$@"( $0bunun bir parçası olmayacak olanlar hariç "$@").
Bu, birlikte -execbulunan yamalar üzerinde etkili olan rasgele karmaşık komut dosyaları oluşturmamıza izin verdiği için birlikte kullanışlıdır find.
Örnek: Belirli bir dosya adı sonekine sahip tüm normal dosyaları bulun ve dosya adı sonekini, soneklerin değişkenlerde tutulduğu başka bir sonekle değiştirin:
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" {} ';'
İçteki betiğin içinde $1dize text, $2dize olacak txtve bizim için $3her ne findbulduysa olacaktır. Parametre genişlemesi ${3%.$1}yol adını alır ve sonekini .textondan kaldırır .
Veya, dirname/ kullanarak basename:
find . -type f -name "*.$from" -exec sh -c '
mv "$3" "$(dirname "$3")/$(basename "$3" ".$1").$2"' sh "$from" "$to" {} ';'
veya, dahili komut dosyasına eklenen değişkenlerle:
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" {} ';'
Bu son varyasyonda, değişkenlerin fromve toalt kabuktaki değişkenlerin harici komut dosyasında aynı ada sahip değişkenlerden farklı olduğunu unutmayın.
Yukarıdaki isteğe bağlı bir karmaşık komut çağrı doğru yolu -execile find. findGibi bir döngüde kullanma
for pathname in $( find ... ); do
hata eğilimli ve inelegant (kişisel görüş). Dosya adlarını boşluklarda bölüyor, dosya ismini globbing'i çağırıyor ve ayrıca kabuğun findilk tekrarını çalıştırmadan önce tüm sonucunu genişletmeye zorluyor .
Ayrıca bakınız:
kullanma -exec ... {} +
;Sonunda ile ikame edilebilir +. Bu find, verilen komutu her bulunan yol adı için bir defadan çok mümkün olduğu kadar çok argümanla (bulunan yol adlarıyla) çalıştırmaya neden olur . Dize {} bunun +çalışması için hemen önce gerçekleşmesi gerekir .
find . -type f -name '*.txt' \
-exec grep -q 'hello' {} ';' \
-exec cat {} +
Burada, findortaya çıkan yol adlarını toplayacak ve bir catkerede mümkün olduğunca çoğunu çalıştıracaksınız .
find . -type f -name "*.txt" \
-exec grep -q "hello" {} ';' \
-exec mv -t /tmp/files_with_hello/ {} +
Aynı şekilde, burada mvmümkün olduğunca az sayıda idam olacak. Bu son örnek mvcoreutil'den GNU gerektiriyor (bu -tseçeneği destekliyor ).
Kullanarak -exec sh -c ... {} +aynı zamanda karmaşık olan rasgele bir komut ile yol adlarının kümesi üzerinde döngü için etkili bir yoldur.
Temel bilgiler kullanımdakiyle aynıdır -exec sh -c ... {} ';', ancak komut dosyası artık daha uzun bir argüman listesi alıyor. Bunlar "$@"betiğin içinde ilmek alınarak ilmeklenebilir .
Dosya adı soneklerini değiştiren son bölümden örnek:
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" {} +
kullanma -execdir
Ayrıca -execdir(çoğu finddeğişken tarafından uygulanır , ancak standart bir seçenek değildir).
Bu -exec, verilen kabuk komutunun, mevcut çalışma dizini olarak bulunan yol adının dizini ile yürütüldüğü ve bulunan yol adının bulunduğu yol adının bulunduğu yol işaretiyle çalıştırılan farkla aynı şekilde çalışır {}(ancak GNU find, taban adının yanında ./, BSD ile findbunu yapmayacağım).
Örnek:
find . -type f -name '*.txt' \
-execdir mv {} done-texts/{}.done \;
Bu, her bulunan *.txt-file dosyasını, dosyanın bulunduğu dizindeki önceden var olan bir done-textsalt dizine taşır . Dosya ayrıca ona sonek eklenerek yeniden adlandırılır ..done
Bu, -execdosyanın {}yeni adını oluşturmak için bulunan dosyanın adının adını almak zorunda kalacağımız için biraz daha zor olacaktır . Dizini düzgün bir şekilde {}bulmak için done-textsdizin ismine de ihtiyacımız var .
Bununla birlikte -execdir, bazı şeyler daha kolay hale gelir.
Bunun -execyerine kullanarak ilgili işlem -execdirbir alt kabuk kullanmak zorunda kalacak:
find . -type f -name '*.txt' -exec sh -c '
for name do
mv "$name" "$( dirname "$name" )/done-texts/$( basename "$name" ).done"
done' sh {} +
veya,
find . -type f -name '*.txt' -exec sh -c '
for name do
mv "$name" "${name%/*}/done-texts/${name##*/}.done"
done' sh {} +