Tente:
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
Se os diretórios estiverem especificados em $@
, use:
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
Como funciona
-
find dir1 dir2 dir3 -maxdepth 1 -type f -printf '%h\n'
Isso procura todos os arquivos regulares nos diretórios dir1, dir2 e dir3. Para cada arquivo encontrado, seu diretório é impresso.
-maxdepth 1
(opcional) informa para não mergulhar em subdiretórios.-type f
diz ao achado para relatar somente arquivos regulares. Para cada arquivo encontrado,-printf '%h\n'
informa para localizar o diretório no qual o arquivo está. -
awk '{c[$0]++} END{for (dir in c) printf "%6i %s\n",c[dir],dir}'
Isso conta o número de vezes que cada diretório aparece na entrada. Depois de ler toda a entrada, imprime os totais.
Usamos o array associativo
c
para contar o número de vezes que cada diretório é visto. No awk,$0
é o conteúdo da linha atual sendo lida.c[$0]
é o número de vezes que a linha foi vista até agora.c[$0]++
de incrementos que contam por um. -
sort -n
Isso classifica a saída em ordem crescente de contagem de arquivos. (
-n
diz ao sort para numericamente em vez de alfabeticamente).
Exemplo
Suponhamos que temos esses diretórios com esses arquivos:
$ 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
Nosso comando produz a saída:
$ 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
Melhoria: Adicionando uma linha total
$ 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
Para suprimir a impressão de TOTAL se houver apenas um diretório na saída:
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
Incluir diretórios vazios na saída
Para incluir também diretórios vazios:
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
Como exemplo, vamos considerar um diretório vazio:
$ ls dir4
E, vamos definir $@
:
$ set -- dir4
Agora, vamos executar nosso código:
$ 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
Vamos tentar novamente com dois diretórios:
$ 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