Jeśli to zrobię ls -1 target_dir | wc -l
, dostanę liczbę plików w katalogu. Uważam to za nieco kłopotliwe. Czy istnieje bardziej elegancki lub zwięzły sposób?
ubuntu
command-line
filesystems
codecowboy
źródło
źródło
ls
już podaje całkowitą liczbę, więc co powiesz nals -l | head -1
? Ustaw go jako alias, jeśli chcesz czegoś krótszego.ls -l
oznaczają całkowity rozmiar plików, a nie liczbę plików.ls | wc -l
będzie niepoprawna, jeśli nazwy plików zawierają znaki nowej linii.stat -c %h .
podaje te same informacje, cols -ld . | cut -d" " -f 2
Odpowiedzi:
Zakładając, że bash 4+ (który ma każda obsługiwana wersja Ubuntu):
Nazwij to jak
num_files [dir]
.dir
jest opcjonalny, w przeciwnym razie korzysta z bieżącego katalogu. Twoja oryginalna wersja nie uwzględnia ukrytych plików, więc też nie. Jeśli tego chcesz,shopt -s dotglob
wcześniejset -- *
.Twój oryginalny przykład obejmuje nie tylko zwykłe pliki, ale także katalogi i inne urządzenia - jeśli naprawdę chcesz tylko zwykłe pliki (w tym dowiązania symboliczne do zwykłych plików), musisz je sprawdzić:
Jeśli masz GNU find, coś takiego jest również opcją (zwróć uwagę, że dotyczy to ukrytych plików, czego nie zrobiło twoje pierwotne polecenie):
(zmień
-type
na,-xtype
jeśli chcesz liczyć również dowiązania symboliczne do zwykłych plików).źródło
set
zawiedzie, jeśli jest bardzo wiele plików? Myślę, że być może będziesz musiał użyćxargs
kodu sumującego, aby to zadziałało w ogólnym przypadku.shopt -s dotglob
jeśli chcesz, aby pliki zaczynające się.
od zliczaniaset
że w tych okolicznościach zawiedzie, ponieważ tak naprawdę nie robimyexec
. To znaczy, w moim systemie,getconf ARG_MAX
daje 262144, ale jeśli to zrobiętest_arg_max() { set -- {1..262145}; echo $#; }; test_arg_max
, z radością odpowiada 262145.-maxdepth
nie jest POSIX.f=(target_dir/*);echo ${#f[*]}
działa poprawnie dla pliku ze spacjami, znakami nowej linii itp. w nazwie.
źródło
ls
jest wielokolumnowy tylko wtedy, gdy wysyła bezpośrednio do terminala, możesz usunąć opcję „-1”, możesz usunąćwc
opcję „-l”, odczytaj tylko pierwszą wartość (leniwe rozwiązanie, nie może być stosowane do dowodów prawnych, dochodzenia kryminalne, misje krytyczne, operacje taktyczne ...).źródło
wc
aby uzyskać liczbę plików nawet w trywialnym przypadku, więc jak to w ogóle rozwiązanie?target
jest globem , który po rozwinięciu zawiera pewne rzeczy, które zaczynają się od łączników. Na przykład stwórz nowy katalog, wejdź do niego i zróbtouch -- {1,2,3,-a}.txt && ls *|wc
(NB: użyj,rm -- *.txt
aby usunąć te pliki.)wc -l
? W przeciwnym razie otrzymasz wynik nowej linii, słowa i bajtówls
. Tak powiedział David Richerby: Musisz to jeszcze raz przeanalizować.wc
bez argumentów, że nie musisz analizować, jeśli twój mózg wie, że pierwszym argumentem jest nowa linia.Jeśli szukasz zwięzłości (zamiast dokładnej poprawności w przypadku plików z nowymi liniami w nazwach itp.), Zalecam po prostu aliasing
wc -l
dolc
(„liczba wierszy”):Jak zauważyli inni, nie potrzebujesz takiej
-1
opcjils
, ponieważ jest to automatyczne, gdyls
piszesz do potoku. (Chyba że maszls
alias, aby zawsze używać trybu kolumnowego. Widziałem to wcześniej, ale niezbyt często).lc
Alias jest bardzo przydatny w ogóle, a na to pytanie, jeśli spojrzeć na „Count bieżący katalog” sprawy,ls|lc
jest tak zwięzłe, jak można dostać.źródło
Jak dotąd podejście Aarona jest bardziej zwięzłe niż twoje. Bardziej poprawna wersja twojego podejścia może wyglądać następująco:
Rekurencyjnie wyświetla listę wszystkich plików - nie katalogów - po jednym w wierszu, w tym .dotfiles pod bieżącym katalogiem, używając globusów powłoki w razie potrzeby do zastąpienia znaków niedrukowalnych. grep odfiltrowuje wszystkie katalogi nadrzędne lub ... lub * / lub puste wiersze - więc powinien być tylko jeden wiersz na plik - całkowita liczba grep do ciebie wraca. Jeśli chcesz również uwzględnić katalogi potomne:
Usuń
-R
w obu przypadkach, jeśli nie chcesz wyników rekurencyjnych.źródło
find
. Jeśli chcesz tylko zliczać, powinno to działać:find -mindepth 1 -maxdepth 1 -printf '\n'|wc -l
(usuń elementy sterujące głębokością, aby uzyskać rekurencyjne wyniki).find . \! -name . -prune | wc -l
- co oczywiście nadal nie działa.printf
instrukcja wypisuje stały ciąg (nowy wiersz), który w ogóle nie zawiera nazwy pliku, więc wyniki są niezależne od dziwnych nazw plików. Oczywiście tej sztuczki nie da się zrobić za pomocą,find
która nie obsługujeprintf
.find .//. \!. -name . -prune | grep -c '^\.//\.'
/
ponieważ jest to jedyny inny znak, który nie może pojawić się w nazwach plików,.//.
sekwencja gwarantuje pojawienie się dokładnie raz dla każdego pliku, prawda? kilka pytań - dlaczego.//.
i dlaczego-prune
? kiedy to by się różniłofind . \! -name . | grep -c '^\.'
? (zakładam, że.
w twoim\!.
jest literówka.)