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
-exec
Seç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ı find
gerekir (daha sonra başka seçenekler de olabilir). Kabuktan korunmak için ;
, \;
veya olarak belirtilmesi gerekir ';'
, aksi takdirde kabuk find
komutun 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 *.txt
geçerli dizindeki veya altındaki desene uyan tüm normal dosyaları ( ) bulacaktır . Daha sonra dizenin hello
kullanarak 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 cat
için dosyanın içeriğini terminale vermek için çalıştırılır.
Her biri , tıpkı olduğu gibi ve yaptığı -exec
yollarda 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
-name
find
find
hello
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
find
komutun sonunda gerekli değildir ).
-exec
İle birlikte kullanmaksh -c
Yürütülebilir komut -exec
isteğ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. -exec
Kullanarak 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 -c
yerine kullanın sh -c
.
sh -c
/bin/sh
komut 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 -c
kendi 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 apples
gibi mevcuttur $1
ve daha fazla argüman olsaydı, o zaman bunlar şu gibi mevcut olurdu $2
, $3
vs. Listede de mevcut olurdu "$@"
( $0
bunun bir parçası olmayacak olanlar hariç "$@"
).
Bu, birlikte -exec
bulunan 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 $1
dize text
, $2
dize olacak txt
ve bizim için $3
her ne find
bulduysa olacaktır. Parametre genişlemesi ${3%.$1}
yol adını alır ve sonekini .text
ondan 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 from
ve to
alt 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 -exec
ile find
. find
Gibi 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 find
ilk 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, find
ortaya çıkan yol adlarını toplayacak ve bir cat
kerede 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 mv
mümkün olduğunca az sayıda idam olacak. Bu son örnek mv
coreutil'den GNU gerektiriyor (bu -t
seç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 find
değ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 find
bunu 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-texts
alt dizine taşır . Dosya ayrıca ona sonek eklenerek yeniden adlandırılır ..done
Bu, -exec
dosyanı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-texts
dizin ismine de ihtiyacımız var .
Bununla birlikte -execdir
, bazı şeyler daha kolay hale gelir.
Bunun -exec
yerine kullanarak ilgili işlem -execdir
bir 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 {} +