Yanıtlar:
Yalnızca kabuk, kabuk işlevlerinin nasıl çalıştırılacağını bildiğinden, bir işlevi çalıştırmak için bir kabuk çalıştırmanız gerekir. Ayrıca, dışa aktarma işlevinizi işaretlemeniz gerekir export -f
, aksi takdirde alt kabuk bunları devralamaz:
export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;
find . -exec bash -c 'dosomething "$0"' {} \;
o Dosya adlarında boşluk (ve diğer garip karakter) idare edeceğiz ...
export -f
sadece bash'ın bazı sürümlerinde çalışır. /bin/sh
find . | while read file; do dosomething "$file"; done
while read
bir for döngüsü için değiştirerek sorunumu giderdi; for item in $(find . ); do some_function "${item}"; done
Jak'ın yukarıdaki cevabı harika ama kolayca üstesinden gelebilecek birkaç tuzak var:
find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done
Bu, satır beslemesi yerine sınırlayıcı olarak null değerini kullanır, bu nedenle satır beslemeli dosya adları çalışır. Ayrıca -r
, dosya adlarındaki ters eğik çizgiler çalışmadığı sürece ters eğik çizgi çıkışını devre dışı bırakan bayrağı kullanır . Ayrıca, adlardaki IFS
potansiyel sondaki boşluk alanlarının atılmaması için temizlenir .
/bin/bash
ama işe yaramayacak /bin/sh
. Ne yazık.
Alıntıları {}
aşağıda gösterildiği gibi ekleyin :
export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;
Bu find
, örneğin adlarında parantez bulunan dosyalar tarafından döndürülen özel karakterler nedeniyle oluşan hataları düzeltir .
{}
. Bu, çift tırnak içeren bir dosya adı için kırılır. touch '"; rm -rf .; echo "I deleted all you files, haha
. Hata.
-exec bash -c 'echo $0' '{}' \;
kullanılırken Not olduğunu bash -c
, $ 0 İlk argüman değil, komut adıdır.
Artan verimlilik için, birçok kişi xargs
sonuçları toplu olarak işlemek için kullanır , ancak çok tehlikelidir. Bu nedenle, find
sonuçları toplu olarak yürüten alternatif bir yöntem vardı .
Bununla birlikte, bu yöntemin komutun sonunda find
olması gereken POSIX'te bir gereksinim gibi bazı uyarılarla gelebileceğini unutmayın {}
.
export -f dosomething
find . -exec bash -c 'for f; do dosomething "$f"; done' _ {} +
find
birçok sonucu tek bir çağrıya argüman olarak iletir bash
ve for
-loop bu bağımsız değişkenler aracılığıyla yineleyerek işlevi dosomething
bunların her birinde gerçekleştirir.
Yukarıdaki çözüm şu argümanlarda başlar $1
, bu yüzden _
(temsil eden $0
) vardır.
Aynı şekilde, kabul edilen üst cevabın da
export -f dosomething
find . -exec bash -c 'dosomething "$1"' _ {} \;
Bu sadece daha aklı başında değildir, çünkü argümanlar her zaman başlamalıdır $1
, ancak $0
döndürülen dosya adının find
kabuğa özel bir anlamı varsa kullanmak beklenmedik davranışlara yol açabilir .
Bağımsız değişken olarak bulunan her öğeyi ileterek komut dosyasının kendisini aramasını sağlayın:
#!/bin/bash
if [ ! $1 == "" ] ; then
echo "doing something with $1"
exit 0
fi
find . -exec $0 {} \;
exit 0
Komut dosyasını tek başına çalıştırdığınızda, aradığınızı bulur ve kendisini her bir buluntu sonucunu argüman olarak iletir. Komut dosyası bir bağımsız değişkenle çalıştırıldığında, bağımsız değişken üzerindeki komutları yürütür ve sonra çıkar.
find: ‘myscript.sh’: No such file or directory
eğer başarısız olur bahsetmiyorum bash myscript.sh
...
Geçerli dizindeki tüm dosyalarda belirli bir komutu yürütecek bir bash işlevi arayanlar için, yukarıdaki cevaplardan birini derledim:
toall(){
find . -type f | while read file; do "$1" "$file"; done
}
Boşluk içeren dosya adlarıyla bozulduğunu unutmayın (aşağıya bakın).
Örnek olarak, bu işlevi alın:
world(){
sed -i 's_hello_world_g' "$1"
}
Geçerli dizindeki tüm dosyalarda tüm merhaba örneklerini dünyaya değiştirmek istediğimi varsayalım. Yapardım:
toall world
Dosya adlarındaki herhangi bir sembolle güvende olmak için şunu kullanın:
toall(){
find . -type f -print0 | while IFS= read -r -d '' file; do "$1" "$file"; done
}
(ancak GNU gibi bir find
işleme ihtiyacınız vardır ).-print0
find
Başvuru için, ben bu senaryo kullanarak kaçının:
for i in $(find $dir -type f -name "$name" -exec ls {} \;); do
_script_function_call $i;
done;
Mevcut komut dosyasında find çıktısını alın ve çıktıyı istediğiniz gibi tekrarlayın. Kabul edilen yanıtı kabul ediyorum, ancak komut dosyası dışında işlevi göstermek istemiyorum.
Bir işlevi bu şekilde yürütmek mümkün değildir .
Bunun üstesinden gelmek için işlevinizi bir kabuk betiğine yerleştirebilir ve find
# dosomething.sh
dosomething () {
echo "doing something with $1"
}
dosomething $1
Şimdi bulmak için kullanın:
find . -exec dosomething.sh {} \;
dosomething $1
dosomething "$1"
find . -exec bash dosomething.sh {} \;
exec
Veya execdir
( -exec command {} +
) için toplu seçeneği kullanıyorsanız ve tüm konumsal bağımsız değişkenleri almak istiyorsanız , diğer yanıtların bazılarına ekleme ve açıklama sağlamak için , $0
ile işlemeyi göz önünde bulundurmanız gerekir bash -c
. Daha somut olarak, bash -c
yukarıda önerildiği gibi kullanılan aşağıdaki komutu göz önünde bulundurun ve bulduğu her dizinden '.wav' ile biten dosya yollarını yankılar:
find "$1" -name '*.wav' -execdir bash -c 'echo $@' _ {} +
Bash el kitabı diyor ki:
If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, they are assigned to the
positional parameters, starting with $0.
İşte, 'check $@'
komut dizesi ve _ {}
komut dizesinden sonraki argümanlar. Bunun $@
bash içinde 1'den başlayan tüm konum parametrelerine genişleyen özel bir konum parametresi olduğunu unutmayın . Ayrıca -c
seçenekle, ilk bağımsız değişkenin konum parametresine atandığını unutmayın $0
. Bu, ile tüm konumsal parametrelere erişmeye çalışırsanız $@
, yalnızca başlangıç $1
ve bitiş parametrelerini alacaksınız demektir . Dominik'in cevabının, _
parametreyi doldurmak için kukla bir argüman olan nedeni budur, bu nedenle , örneğin parametre genişletmeyi veya bu yanıttaki gibi for döngüsünü $0
kullanırsak, istediğimiz tüm argümanlar daha sonra kullanılabilir $@
.
Tabii ki, kabul edilen cevaba benzer şekilde, bash -c 'shell_function $0 $@'
açıkça geçerek de işe yarayacaktır $0
, ancak yine de, $@
beklendiği gibi çalışmayacağını aklınızda bulundurmanız gerekir .
Doğrudan değil, hayır. Bul, kabuğunuzda değil ayrı bir işlemde yürütülüyor.
İşlevinizle aynı işi yapan bir kabuk komut dosyası oluşturun ve bunu yapabilirsiniz -exec
.
$0
.