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 -fsadece bash'ın bazı sürümlerinde çalışır. /bin/sh
find . | while read file; do dosomething "$file"; done
while readbir 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 IFSpotansiyel sondaki boşluk alanlarının atılmaması için temizlenir .
/bin/bashama 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 xargssonuçları toplu olarak işlemek için kullanır , ancak çok tehlikelidir. Bu nedenle, findsonuçları toplu olarak yürüten alternatif bir yöntem vardı .
Bununla birlikte, bu yöntemin komutun sonunda findolması 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' _ {} +
findbirçok sonucu tek bir çağrıya argüman olarak iletir bashve for-loop bu bağımsız değişkenler aracılığıyla yineleyerek işlevi dosomethingbunları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 $0döndürülen dosya adının findkabuğ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 directoryeğ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 findişleme ihtiyacınız vardır ).-print0find
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 $1dosomething "$1"find . -exec bash dosomething.sh {} \;
execVeya 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 , $0ile işlemeyi göz önünde bulundurmanız gerekir bash -c. Daha somut olarak, bash -cyukarı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 -cseç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ıç $1ve 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ü $0kullanı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.