Я хочу создать функцию 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 на $@
, но я бы лучше нашел более простое решение. Если вы можете также помочь мне включить размер каждого каталога. Вы бы сделали меня по-настоящему счастливым!
Попытка:
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
find dir1 dir2 dir3 -maxdepth 1 -type f -printf '%h\n'
Это ищет все регулярные файлы в каталогах 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}'
Это считает количество раз, каждый каталог появляется на входе. После того, как весь вход был считан, он печатает общие количества.
Мы используем ассоциативный массив c
для подсчета количества раз, каждый каталог замечен. В awk, $0
содержание текущей считанной строки. c[$0]
количество раз, что строка была замечена до сих пор. c[$0]++
инкременты то количество одним.
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