Znajdź katalogi zawierające określoną liczbę plików

14

Miałem nadzieję, że będę w stanie to zrobić za pomocą findpolecenia, ale nie widzę w instrukcji żadnego testu na to, co chcę. Chciałbym móc znaleźć katalogi w katalogu roboczym, które zawierają mniej niż, więcej niż dokładnie lub określoną przeze mnie liczbę.

find . -filecount +10 # any directory with more than 10 entries
find . -filecount 20 # any directory with exactly 20 entries

Ale niestety nie ma takiej opcji.

Paul Ruane
źródło
spróbuj czegoś takiego jak "ls -al | wc -l | grep"
Vanadis

Odpowiedzi:

17

Możesz spróbować, aby uzyskać nazwy podkatalogów i liczbę zawartych w nich plików / katalogów:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \;

Jeśli chcesz zrobić to samo dla wszystkich podkatalogów (wyszukiwanie rekurencyjne), użyj tego:

find . -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \;

Aby wybrać katalogi, które mają dokładnie 10 plików:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
  awk '$NF==10'

10 lub więcej:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
 awk '$NF>=10'

10 lub mniej:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
 awk '$NF<=10'

Jeśli chcesz zachować tylko nazwę katalogu (na przykład chcesz przesłać go do innego procesu poniżej, jak sugeruje @evilsoup), możesz użyć tego:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{}\t'; ls '{}' | wc -l" \; | 
 awk -F"\t" '$NF<=10{print $1}'
terdon
źródło
1
Myślę, że przydatne może być włączenie polecenia awk, aby odciąć liczbę plików (tj. Ostatnią kolumnę oddzieloną spacjami), na wypadek, gdyby pytający chciał przesłać dane wyjściowe do czegoś innego.
evilsoup
1
@evilsoup dobry pomysł, gotowe.
terdon
Do obsługi białych znaków i znaków specjalnych w nazwach katalogów; spróbuj odwrócić użycie pojedynczych i podwójnych cudzysłowów jako takich:find . -type d -exec bash -c 'echo -ne "{} "; ls "{}" | wc -l' \; | awk '$NF<=10'
Håvard Geithus
3

Aby wyświetlić listę bezpośrednich podkatalogów zawierających dokładnie $NUM pliki.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]==num) printf "%s\n", line}'

Aby wyświetlić listę bezpośrednich podkatalogów zawierających więcej niż $NUMpliki.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]>num) printf "%s\n", line}'

Aby wyświetlić listę bezpośrednich podkatalogów zawierających mniej niż $NUMpliki.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]<num) printf "%s\n", line}'

Elementy są zakończone znakiem zerowym \0, więc nazwy plików zawierające znaki nowej linii lub inne białe znaki będą interpretowane poprawnie. %hDrukuje każdego pliku dirname. awknastępnie używa tablicy, aby policzyć, ile razy napotyka każdy katalog, drukując go, jeśli warunki są spełnione.

Należy pamiętać, że żadne z wyżej wymienionych poleceń nie wyświetla katalogów zawierających pliki zerowe. Zauważ też, że przez plik mam na myśli zwykłe pliki, a nie łącza, katalogi, gniazda, bloki, nazwane potoki itp.

Próbowałem to zrobić tak prosto, jak to możliwe. Jeśli chcesz znaleźć rekurencyjne podkatalogi lub znajdujące się w nich pliki, wymagane jest zmodyfikowane polecenie. Istnieje zbyt wiele możliwości, aby wymienić je wszystkie.

Sześć
źródło
2

Spróbuj tego:

[„znajdź. | wc -l` -eq 10] && echo „Znaleziono”

[„znajdź. | wc -l` -gt 10] && echo „Znaleziono”

[„znajdź. | wc -l` -lt 10] && echo „Znaleziono”

W tych przykładach możesz sprawdzić, czy katalog CURRENT zawiera dokładnie 10, więcej niż 10 i mniej niż 10 plików / katalogów. Jeśli chcesz sprawdzić kilka katalogów, po prostu użyj pętli.

wrzesień
źródło
Twoje rozwiązanie liczy również bieżący katalog ( .), możesz chcieć odpowiednio zmodyfikować.
terdon
Podoba mi się sens tej odpowiedzi (ponieważ jestem żarłokiem do robienia rzeczy w powłoce), ale lepiej byłoby użyć testu wc -l < <(printf %s\\n ./*)lub printf %s\\n ./* | wc -lw jego wnętrzu, aby uniknąć niepotrzebnego findpołączenia. Pozwoli to również uniknąć problemu, który zauważył @terdon, polegającego .na uwzględnieniu wyniku. Jednak miałby również problem z ignorowaniem plików zaczynających się na .; Rozwiązałbym to za pomocą shopt -s dotglob(aby dopasować globusy do plików zaczynających się od ., ale nie .lub ..).
evilsoup
@terdon To nie jest ważne. To nie jest ostateczne rozwiązanie, tylko przykład, pomysł. Możesz -1 lub zmienić 10 na 11 w ostatecznej wersji.
wrzesień
Wiem, a pomysł jest dobry, dlatego zasugerowałem.
terdon
@ terdon. Dziękuję Ci. Może być wiele różnych wymagań, takich jak: Policz tylko pliki, ale nie katalogi, łącza lub twarde łącza. Policz lub nie pliki w podkatalogach. Policz ukryte pliki (takie jak .bashrc) ... ... aby Twoje wyrażenie mogło być bardzo długie. :)
września