1.
İlki:
for f in *; do
echo "$f"
done
denilen dosyalar için başarısız -n
, -e
ve benzeri varyantları -nene
dosya adları ters eğik çizgi içeren ve bazı bash dağıtımları ile.
İkinci:
find * -prune | while read f; do
echo "$f"
done
daha fazla vaka için başarısız olur (çağrılan dosyalar !
, -H
, -name
, (
... başlangıç veya bitiş kurusıkı veya yeni satır karakterleri içeren, dosya adları)
Genişleyen kabuk *
,find
argüman olarak aldığı dosyaları başka bir şey yapmaz Sen de kullanmış olabilir printf '%s\n'
olarak hangi yerine printf
yerleşik da önleyeceğini olduğunu çok fazla bağımsız değişken potansiyel hata.
2.
Genişlemesi *
sıralanır, sıralamaya ihtiyacınız yoksa biraz daha hızlı hale getirebilirsiniz. İçinde zsh
:
for f (*(oN)) printf '%s\n' $f
ya da sadece:
printf '%s\n' *(oN)
bash
Söyleyebileceğim kadarıyla eşdeğeri yok, o yüzden başvurman gerekiyor find
.
3.
find . ! -name . -prune ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
(bir GNU / BSD kullanarak yukarıda -print0
standart olmayan bir uzantı kullanılarak).
Bu hala bir bulma komutunun oluşturulmasını ve yavaş bir while read
döngü kullanılmasını içerir, bu nedenle for
dosya listesi çok büyük olmadıkça döngü kullanmaktan daha yavaş olacaktır .
4.
Ayrıca, joker karakter genişlemesinin aksine , her dosya find
için bir lstat
sistem çağrısı yapar; bu nedenle, sıralama dışı işlemlerin bunu telafi etmesi olası değildir.
GNU / BSD ile find
, aşağıdakileri -maxdepth
kazandıran bir optimizasyonu tetikleyecek uzantılarını kullanarak önlenebilir lstat
:
find . -maxdepth 1 ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
Çünkü find
dosya adlarını bulduktan hemen sonra çıkarmaya başlar (stdio çıktı arabelleği hariç), döngüde ne yaparsanız zaman alıcı ve dosya adlarının listesi bir stdio arabasından daha fazlaysa daha hızlı olabilir. / 8 kB). Bu durumda, döngü içindeki işlem find
tüm dosyaları bulma işlemini bitirmeden önce başlayacaktır . GNU ve FreeBSD sistemlerinde, stdbuf
bunun daha erken olmasını sağlamak için kullanabilirsiniz (stdio tamponlamayı devre dışı bırakarak).
5.
Her dosya için komut çalıştırmanın POSIX / standart / taşınabilir yolu yüklemi find
kullanmaktır -exec
:
find . ! -name . -prune ! -name '.*' -exec some-cmd {} ';'
Durumunda echo
kabuk bir yerleşik sürümüne sahip olacak şekilde kabuğunda döngü yapmaktan daha az verimli olsa, echo
ise find
yeni bir süreç yumurtlamaya ve yürütmek gerekir /bin/echo
her dosya için içinde.
Birkaç komut çalıştırmanız gerekirse, şunları yapabilirsiniz:
find . ! -name . -prune ! -name '.*' -exec cmd1 {} ';' -exec cmd2 {} ';'
Ancak , başarılı cmd2
olursa cmd1
, yürütüldüğüne dikkat edin .
6.
Her dosya için karmaşık komutları çalıştırmanın kurallı bir yolu, aşağıdakileri içeren bir kabuk çağırmaktır -exec ... {} +
:
find . ! -name . -prune ! -name '.*' -exec sh -c '
for f do
cmd1 "$f"
cmd2 "$f"
done' sh {} +
O zamanlar, yerleşik olanını kullandığımızdan ve sürüm mümkün olduğu kadar az çıktığından echo
beri verimli olmaya geri döndük .sh
-exec +
sh
7.
In 200.000 dosyaları ile bir dizin benim testlerde ext4 kısa adlarla, zsh
bir (paragraf 2.) İlk basit ardından uzak hızlı gereğidir for i in *
döngü (her zamanki gibi olsa bash
çok daha yavaş diğer kabukları daha o içindir).
find
bulduğu dosyaları açmaz. Çok sayıda dosya için sizi burada ısırmayı görebildiğim tek şey ARG_MAX .