Krótka odpowiedź:
\ls -afq | wc -l
(Obejmuje to, .
a ..
więc odejmij 2.)
Gdy wyświetlasz listę plików w katalogu, mogą się zdarzyć trzy typowe rzeczy:
- Wyliczanie nazw plików w katalogu. Jest to nieuniknione: nie można policzyć plików w katalogu bez ich wyliczenia.
- Sortowanie nazw plików. Powtarzają to symbole wieloznaczne powłoki i
ls
polecenie.
- Wywoływanie w
stat
celu pobrania metadanych dotyczących każdej pozycji katalogu, na przykład, czy jest to katalog.
# 3 jest zdecydowanie najdroższym, ponieważ wymaga załadowania i-węzła dla każdego pliku. Dla porównania, wszystkie nazwy plików potrzebne dla nr 1 są przechowywane w zwięzłej formie w kilku blokach. # 2 marnuje trochę czasu procesora, ale często nie przeszkadza.
Jeśli w nazwach plików nie ma nowego wiersza, prosty ls -A | wc -l
informuje, ile plików znajduje się w katalogu. Uważaj, że jeśli masz alias ls
, może to wywołać wywołanie stat
(np. ls --color
Lub ls -F
znać typ pliku, który wymaga wywołania stat
), a więc z linii poleceń, zadzwoń command ls -A | wc -l
lub \ls -A | wc -l
unikaj aliasu.
Jeśli w nazwie pliku znajdują się znaki nowej linii, to czy nowe linie są na liście, czy nie, zależy od wariantu Uniksa. Coreutils GNU i BusyBox domyślnie wyświetlają się ?
dla nowej linii, więc są bezpieczne.
Zadzwoń, ls -f
aby wyświetlić listę wpisów bez ich sortowania (# 2). To automatycznie się włącza -a
(przynajmniej w nowoczesnych systemach). -f
Opcja jest w POSIX ale ze statusem opcjonalnego; większość implementacji obsługuje to, ale nie BusyBox. Ta opcja -q
zastępuje znaki niedrukowalne, w tym znaki nowego wiersza, przez ?
; jest POSIX, ale nie jest obsługiwany przez BusyBox, więc pomiń go, jeśli potrzebujesz obsługi BusyBox kosztem przeliczania plików, których nazwa zawiera znak nowej linii.
Jeśli katalog nie ma podkatalogów, wówczas większość wersji find
nie wywoła stat
swoich wpisów (optymalizacja katalogu liści: katalog z liczbą linków 2 nie może mieć podkatalogów, więc find
nie trzeba wyszukiwać metadanych wpisów, chyba że stan taki, jak tego -type
wymaga). Więc find . | wc -l
jest przenośny, szybki sposób liczyć plików w katalogu, pod warunkiem, że katalog ma podkatalogi, a nie nazwa pliku zawiera znak nowej linii.
Jeśli katalog nie ma podkatalogów, ale nazwy plików mogą zawierać znaki nowej linii, wypróbuj jeden z nich (drugi powinien być szybszy, jeśli jest obsługiwany, ale może nie być zauważalny).
find -print0 | tr -dc \\0 | wc -c
find -printf a | wc -c
Z drugiej strony nie używaj, find
jeśli katalog ma podkatalogi: nawet find . -maxdepth 1
wywołuje stat
każdy wpis (przynajmniej z GNU find i BusyBox find). Unikasz sortowania (# 2), ale płacisz cenę za wyszukiwanie i-węzłów (# 3), które zabija wydajność.
W powłoce bez zewnętrznych narzędzi można uruchomić zliczanie plików w bieżącym katalogu za pomocą set -- *; echo $#
. Pomija to pliki kropkowe (pliki, których nazwa zaczyna się od .
) i zgłasza 1 zamiast 0 w pustym katalogu. Jest to najszybszy sposób na zliczanie plików w małych katalogach, ponieważ nie wymaga uruchomienia programu zewnętrznego, ale (oprócz zsh) marnuje czas na większe katalogi z powodu kroku sortowania (# 2).
W bash jest to niezawodny sposób na policzenie plików w bieżącym katalogu:
shopt -s dotglob nullglob
a=(*)
echo ${#a[@]}
W ksh93 jest to niezawodny sposób na zliczanie plików w bieżącym katalogu:
FIGNORE='@(.|..)'
a=(~(N)*)
echo ${#a[@]}
W zsh jest to niezawodny sposób na policzenie plików w bieżącym katalogu:
a=(*(DNoN))
echo $#a
Jeśli masz mark_dirs
zestaw opcji, należy ją wyłączyć: a=(*(DNoN^M))
.
W dowolnej powłoce POSIX jest to niezawodny sposób na policzenie plików w bieżącym katalogu:
total=0
set -- *
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
set -- .[!.]*
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
set -- ..?*
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
echo "$total"
Wszystkie te metody sortują nazwy plików, z wyjątkiem jednej zsh.
ls -l|wc -l
byłby wyłączony o jeden ze względu na całkowitą liczbę bloków w pierwszym wierszuls -l
wyniku