Liczba plików w każdym podkatalogu

22

Chciałbym, aby polecenie BASH wyświetlało tylko liczbę plików w każdym podkatalogu katalogu.

Na przykład w katalogu /tmpnie są dir1, dir2... Chciałbym zobaczyć:

`dir1` : x files 
`dir2` : x files ...
Jldupont
źródło

Odpowiedzi:

33

Zakładając, że chcesz tylko rekurencyjną liczbę plików, a nie katalogów i innych typów, coś takiego powinno działać:

find . -maxdepth 1 -mindepth 1 -type d | while read dir; do
  printf "%-25.25s : " "$dir"
  find "$dir" -type f | wc -l
done
Thor
źródło
Ponadto pojawia się komunikat „znajdź: ostrzeżenie: podano opcję -maxdepth po argumencie innym niż -typ -type, ale opcje nie są pozycjonowane (-maxdepth wpływa na testy określone przed nim, a także na testy określone po nim). Określ opcje przed innymi argumentami. ”
jldupont
2
Obie dotychczas podane odpowiedzi dadzą nieprawidłowe wyniki w mało prawdopodobnym przypadku, gdy istnieją pliki, których nazwy zawierają znaki nowego wiersza. Możesz sobie z tym poradzić za pomocą find... -print0 | xargs -0....
Scott,
@ jldupont: przenieś argumenty głębokości przed „typ d”, zredagowałem odpowiedź.
Thor
Tak, i pozwól mi dodać informację, że to doskonałe rozwiązanie nie przyjmuje żadnych zewnętrznych zmiennych, a zatem będzie działać z bash alias!!
składniaerror
szybko, a po instalacji sort -rn -k 2,2 -t$':'dostajesz listę DESC
Andre Figueiredo
14

To zadanie tak mnie zafascynowało, że sam chciałem znaleźć rozwiązanie. Nie zajmuje to nawet czasu i MOŻE być szybszy w wykonywaniu. Nie trzeba dodawać, że wysiłki Thora pomogły mi bardzo szczegółowo zrozumieć rzeczy.

Oto moje:

find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo "{} : $(find "{}" -type f | wc -l)" file\(s\)' \;

Z jakiegoś powodu wygląda skromnie, ponieważ jest o wiele potężniejszy niż wygląda. :-)

Jeśli jednak chcesz dołączyć to do swojego .bash_aliasespliku, musi on wyglądać następująco:

alias somealias='find . -maxdepth 1 -mindepth 1 -type d -exec sh -c '\''echo "{} : $(find "{}" -type f | wc -l)" file\(s\)'\'' \;'

Zwróć uwagę na bardzo trudną obsługę zagnieżdżonych pojedynczych cudzysłowów. I nie, nie można użyć podwójnego cudzysłowu jako sh -cargumentu.

błąd składni
źródło
Jest wolniejszy, ponieważ wywołuje / bin / sh dla każdego katalogu. Możesz to sprawdzić za pomocą strace -fc script. Twoja wersja generuje około 70% więcej wywołań systemowych. +1 za krótszy kod :-)
Thor,
1
zainspirowany tym; posortowane według liczby plików:find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'echo "$(find "{}" -type f | wc -l)" {}' \; | sort -nr
mnagel
7
find . -type f | cut -d"/" -f2 | uniq -c

Wyświetla listę folderów i plików w bieżącym folderze z liczbą plików znajdujących się poniżej. Szybkie i przydatne IMO. (pliki pokazują z liczbą 1).

nie dziekuje
źródło
1
Co powiesz na małe wyjaśnienie, jak to działa? :)
C0deDaedalus
1
Wielkie dzieki! Możesz dodać | sort -rndo sortowania podkatalogów według liczby plików.
Dennis Golomazov
1

Korzystanie z funkcji wyszukiwania jest zdecydowanie najlepszym rozwiązaniem, jeśli chcesz liczyć rekurencyjnie, ale jeśli chcesz tylko liczbę plików bezpośrednio w określonym katalogu:

ls dir1 | wc -l

jrajav
źródło
Nie chcę tego robić dla każdego z 1000 katalogów, które tam mam ...
jldupont
Następnie użyj xargs. ls -d */ | xargs -n1 ls | wc -l(Użyj jednak odpowiedzi, którą zaakceptowałeś, jeśli już działa! To jest po prostu i teraz wiesz.)
jrajav
twoja propozycja nie pokazała żadnych rezultatów przez wiele sekund, a odpowiedź, którą zaakceptowałem, zrobiła to.
jldupont
@ jrajav to podejście absolutnie zawodzi w przypadku katalogów z białymi znakami. Właśnie dlatego findjest tak ważny. (nie mówiąc już -print0i xargs -0już wskazane przez Scotta w drugiej odpowiedzi)
SyntaxError
1
find . -mindepth 1 -type d -print0 | xargs -0 -I{} sh -c 'printf "%4d : %s\n" "$(find {} -type f | wc -l)" "{}"'

Często muszę liczyć liczbę plików w moich podkatalogach i używać tego polecenia. Wolę, aby liczba pojawiła się pierwsza.

Teddy Katayama
źródło
0

Czego używam ... To tworzy tablicę wszystkich podkatalogów w tym, który podajesz jako parametr. Wydrukuj podkatalog i liczbę tego samego podkatalogu, aż wszystkie podkatalogi zostaną przetworzone.

#!/bin/bash    
directories=($(/bin/ls -l $1 | /bin/grep "^d" | /usr/bin/awk -F" " '{print $9}'))

for item in ${directories[*]}
    do
        if [ -d "$1$item" ]; then
            echo "$1$item"
            /bin/ls $1$item | /usr/bin/wc -l
        fi
    done
derberlinersmurf
źródło
0

Możesz użyć tego kodu python. Uruchom interpreter, uruchamiając python3i wklej to:

folder_path = '.'
import os, glob
for folder in sorted(glob.glob('{}/*'.format(folder_path))):
    print('{:}: {:>8,}'.format(os.path.split(folder)[-1], len(glob.glob('{}/*'.format(folder)))))

Lub wersja rekurencyjna dla zagnieżdżonych zliczeń:

import os, glob
def nested_count(folder_path, level=0):
    for folder in sorted(glob.glob('{}/'.format(os.path.join(folder_path, '*')))):
        print('{:}{:}: {:,}'.format('    '*level, os.path.split(os.path.split(folder)[-2])[-1], len(glob.glob(os.path.join(folder, '*')))))
        nested_count(folder, level+1)
nested_count('.')

Przykładowe dane wyjściowe:

>>> figures: 5
>>> misc: 1
>>> notebooks: 5
>>>     archive: 65
>>>     html: 12
>>>     py: 12
>>>     src: 14
>>> reports: 1
>>>     content: 6
>>> src: 1
>>>     html_download: 1
AlexG
źródło