Como obter o número de arquivos em cada diretório?

3

Eu quero fazer uma função bash que se comportaria da mesma forma como wc -l se comporta em vários arquivos para contar seu número de linhas na contagem do número de arquivos em um conjunto de diretórios. Como wc -l funciona:

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

Como eu quero que minha função funcione em arquivos:

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

Onde dir {1..3} são 3 diretórios e o número de arquivos mostrados inclui os arquivos ocultos.

O que eu já fiz:

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

Eu posso implementá-lo com um loop for em $@ , mas prefiro encontrar uma solução mais fácil. Se você também pode me ajudar a incluir o tamanho de cada diretório. Você me faria muito feliz!

    
por yukashima huksay 11.01.2018 / 03:48

1 resposta

2

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

  1. 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á.

  2. 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.

  3. 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
    
por John1024 11.01.2018 / 04:47