Как узнать количество файлов в каждом каталоге?

Я хочу создать функцию bash, которая будет вести себя так же, как wc -l для нескольких файлов, чтобы подсчитывать их количество строк при подсчете количества файлов в наборе каталогов. Как работает wc -l:

wc -l test.zip  tt.zip zzz.zip | sort
     17 tt.zip
   2015 test.zip
   6567 zzz.zip
   8599 total

Как я хочу, чтобы моя функция работала с файлами:

count dir1 dir2 dir3 | sort:
      1 dir1
    144 dir2
   1000 dir3
   1145 total

Где dir {1..3} - это 3 каталога и количество файлов показано включает в себя скрытые файлы.

Что я уже сделал:

#/bin/bash
count() {
    if [ "`file -b $1`" == 'directory' ] ; then    
        echo `la "$1" | wc -l`
    else
        wc -l "$@" | sort
    fi
}

Я могу реализовать это с помощью цикла for на $@, но я бы лучше нашел более простое решение. Если вы можете также помочь мне включить размер каждого каталога. Вы бы сделали меня по-настоящему счастливым!

3
задан 11 January 2018 в 10:21

1 ответ

Попытка:

find dir1 dir2 dir3 -maxdepth 1 -type f -printf '%h\n' | awk '{c[$0]++} END{for (dir in c) printf "%6i %s\n",c[dir],dir}' | sort -n

Если каталоги указаны в $@, затем использование:

find "$@" -maxdepth 1 -type f -printf '%h\n' | awk '{c[$0]++} END{for (dir in c) printf "%6i %s\n",c[dir],dir}' | sort -n

Как это работает

  1. find dir1 dir2 dir3 -maxdepth 1 -type f -printf '%h\n'

    Это ищет все регулярные файлы в каталогах dir1, dir2 и dir3. Для каждого найденного файла печатается его каталог.

    -maxdepth 1 (дополнительно) говорит, находят для не дайвинга в подкаталоги. -type f говорит находят, чтобы только сообщить относительно регулярных файлов. Для каждого найденного файла, -printf '%h\n' говорит находят для печати каталога, в котором находится файл.

  2. awk '{c[$0]++} END{for (dir in c) printf "%6i %s\n",c[dir],dir}'

    Это считает количество раз, каждый каталог появляется на входе. После того, как весь вход был считан, он печатает общие количества.

    Мы используем ассоциативный массив c для подсчета количества раз, каждый каталог замечен. В awk, $0 содержание текущей считанной строки. c[$0] количество раз, что строка была замечена до сих пор. c[$0]++ инкременты то количество одним.

  3. sort -n

    Это сортирует вывод в порядке возрастания количества файла. (-n говорит вид виду численно, а не в алфавитном порядке.)

Пример

Давайте предположим, что у нас есть эти каталоги с этими файлами:

$ ls dir{1..3}/*
dir1/a.txt  dir1/c.txt  dir1/e.txt      dir1/f.txt  dir2/b.txt  dir2/d.txt  dir2/f.txt  dir3/b.txt
dir1/b.txt  dir1/d.txt  dir1/file3.txt  dir2/a.txt  dir2/c.txt  dir2/e.txt  dir3/a.txt

Наша команда производит вывод:

$ find dir1 dir2 dir3 -maxdepth 1 -type f -printf '%h\n' | awk '{c[$0]++} END{for (dir in c) printf "%6i %s\n",c[dir],dir}' | sort -n
     2 dir3
     6 dir2
     7 dir1

Улучшение: Добавление строки итогов

$ find dir1 dir2 dir3 -maxdepth 1 -type f -printf '%h\n' | awk '{c[$0]++} END{for (dir in c) {printf "%6i %s\n",c[dir],dir;tot+=c[dir]}; printf "%6i TOTAL",tot }' | sort -n
     2 dir3
     6 dir2
     7 dir1
    15 TOTAL

Для подавления печати ОБЩЕГО КОЛИЧЕСТВА, если существует только один каталог в выводе:

find "$@" -maxdepth 1 -type f -printf '%h\n' | awk '{c[$0]++} END{for (dir in c) {printf "%6i %s\n",c[dir],dir;tot+=c[dir]}; if (length(c)>1)printf "%6i TOTAL",tot }' | sort -n

Включайте пустые каталоги в вывод

Также включать пустые каталоги:

find "$@" -maxdepth 1 -type f -printf '%h\n' | awk 'FNR==NR{c[$0]=0; next} {c[$0]++} END{for (dir in c) {printf "%6i %s\n",c[dir],dir;tot+=c[dir]}; if (length(c)>1)printf "%6i TOTAL",tot }' <(printf "%s\n" "$@") <(cat) | sort -n

Как пример, давайте рассмотрим пустой каталог:

$ ls dir4

И, давайте установим $@:

$ set -- dir4

Теперь, давайте выполним наш код:

$ find "$@" -maxdepth 1 -type f -printf '%h\n' | awk 'FNR==NR{c[$0]=0; next} {c[$0]++} END{for (dir in c) {printf "%6i %s\n",c[dir],dir;tot+=c[dir]}; if (length(c)>1)printf "%6i TOTAL",tot }' <(printf "%s\n" "$@") <(cat) | sort -n
     0 dir4

Давайте попробуем еще раз с двумя каталогами:

$ set --  dir1 dir4
$ find "$@" -maxdepth 1 -type f -printf '%h\n' | awk 'FNR==NR{c[$0]=0; next} {c[$0]++} END{for (dir in c) {printf "%6i %s\n",c[dir],dir;tot+=c[dir]}; if (length(c)>1)printf "%6i TOTAL",tot }' <(printf "%s\n" "$@") <(cat) | sort -n
     0 dir4
     7 dir1
     7 TOTAL
2
ответ дан 11 January 2018 в 10:21

Другие вопросы по тегам:

Похожие вопросы: