1.
Pierwszy:
for f in *; do
echo "$f"
done
nie plików o nazwie -n, -ei warianty jak -neneiz niektórych wdrożeniach bash, ale w nazwach zawierających backslashy.
Drugi:
find * -prune | while read f; do
echo "$f"
done
nie dla jeszcze większej liczby przypadków (plików o nazwie !, -H, -name, (, nazw plików, które rozpoczynają lub kończą się puste lub zawierają znaki nowej linii ...)
To powłoka, która się rozszerza *, findnic nie robi, tylko drukuje pliki, które otrzymuje jako argumenty. Równie dobrze możesz użyć printf '%s\n'zamiast tego, który printfjest wbudowany, aby uniknąć zbyt wielu potencjalnych błędów args .
2)
Rozszerzenie *jest posortowane, możesz je przyspieszyć, jeśli nie potrzebujesz sortowania. W zsh:
for f (*(oN)) printf '%s\n' $f
lub po prostu:
printf '%s\n' *(oN)
basho ile mi wiadomo, nie ma odpowiednika, więc musisz się do niego odwołać find.
3)
find . ! -name . -prune ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
(powyżej przy użyciu -print0niestandardowego rozszerzenia GNU / BSD ).
To wciąż wymaga odrodzenia polecenia find i użycia wolnej while readpętli, więc prawdopodobnie będzie wolniejsza niż użycie forpętli, chyba że lista plików jest ogromna.
4
Ponadto, w przeciwieństwie do rozszerzenia symboli wieloznacznych powłoki, findwykona lstatwywołanie systemowe dla każdego pliku, więc jest mało prawdopodobne, aby brak sortowania to zrekompensował.
W przypadku GNU / BSD findmożna tego uniknąć, stosując ich -maxdepthrozszerzenie, które uruchomi optymalizację oszczędzając lstat:
find . -maxdepth 1 ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
Ponieważ findzaczyna wypisywać nazwy plików, gdy tylko je znajdzie (z wyjątkiem buforowania wyjścia stdio), dlatego może być szybsze, jeśli to, co robisz w pętli, jest czasochłonne, a lista nazw plików to więcej niż bufor stdio (4 / 8 kB). W takim przypadku przetwarzanie w pętli rozpocznie się przed findzakończeniem wyszukiwania wszystkich plików. W systemach GNU i FreeBSD możesz użyć tego, stdbufaby spowodować to wcześniej (wyłączenie buforowania stdio).
5
POSIX / standard / przenośny sposób uruchamiania poleceń dla każdego pliku za findpomocą -execpredykatu:
find . ! -name . -prune ! -name '.*' -exec some-cmd {} ';'
W tym przypadku jest to echojednak mniej wydajne niż wykonywanie pętli w powłoce, ponieważ powłoka będzie miała wbudowaną wersję, echopodczas gdy findbędzie wymagać odrodzenia nowego procesu i wykonania /bin/echow nim dla każdego pliku.
Jeśli chcesz uruchomić kilka poleceń, możesz:
find . ! -name . -prune ! -name '.*' -exec cmd1 {} ';' -exec cmd2 {} ';'
Ale uważaj, że cmd2jest wykonywany tylko wtedy, gdy cmd1się powiedzie.
6.
Kanonicznym sposobem uruchamiania złożonych poleceń dla każdego pliku jest wywołanie powłoki za pomocą -exec ... {} +:
find . ! -name . -prune ! -name '.*' -exec sh -c '
for f do
cmd1 "$f"
cmd2 "$f"
done' sh {} +
Tym razem wracamy do sprawności, echoponieważ używamy shwbudowanego, a -exec +wersja odradza się shjak najmniej.
7
W moich testach katalogu z 200 000 plików o krótkich nazwach na ext4 ten zsh(paragraf 2) jest zdecydowanie najszybszy, a następnie pierwsza prosta for i in *pętla (choć jak zwykle bashjest znacznie wolniejsza niż inne powłoki).
findnie otwiera znalezionych plików. Jedyne, co widzę, gryząc cię tutaj w odniesieniu do dużej liczby plików, to ARG_MAX .