Listar o número de arquivos em cada pasta em que o nome da pasta corresponde a um padrão

3

Eu gostaria de pesquisar recursivamente uma árvore de diretórios e listar o número de arquivos disponíveis em cada pasta que tem um nome correspondente a uma determinada string. De fato, gostaria de retornar resultados de:

ls -l | wc -l

para cada pasta que identifiquei por meio de find .

Código

O código abaixo lista corretamente o número de arquivos em cada pasta que o nome contém a string Magic Data .

find /path/to/cool/stuff                        \         
        -maxdepth 4                             \         
        -type d                                 \         
        -name '*Magic Data*'                    \         
        -print0 | xargs                         \         
                --verbose                       \         
                -0 -I {} ls -l {}               

Eu gostaria de expandi-lo e canalizar os resultados de ls para wc -l .

Tentativa

find /path/to/cool/stuff                        \         
        -maxdepth 4                             \         
        -type d                                 \         
        -name '*Magic Data*'                    \         
        -print0 | xargs                         \         
                --verbose                       \         
                -0 -I {} ls -l {}  | wc -l            

Isso falha e imprime:

ls -l /path/to/cool/stuff/some/folders/Magic Data
ls -l /path/to/cool/stuff/some/folders2/Magic Data

Saída desejada

/path/to/cool/stuff/some/folders/Magic Data  29
/path/to/cool/stuff/some/folders2/Magic Data 30

A saída desejada conteria:

  • Caminho completo para a pasta pesquisada
  • Saída de wc -l , que nesse caso reflete a contagem de arquivos não ocultos
por Konrad 16.07.2018 / 13:29

3 respostas

3

Existem duas maneiras principais de resolver isso:

  1. Modifique o comando find para que ele entre apenas nos diretórios nos quais você está interessado e, em seguida, imprima um único caractere (por exemplo, x ) para cada arquivo encontrado. Em seguida, conte o número desse caractere produzido com wc -l . É mais seguro gerar um caractere do que o nome do caminho, já que nomes de caminho no Unix podem conter novas linhas. Essa solução é um pouco complicada, pois envolve usar -prune para ignorar diretórios nos quais não estamos interessados ou, alternativamente, ! -path .

  2. Encontre os diretórios como você fez até agora, mas use um script in-line para fazer a contagem de arquivos. Isso é mais simples e o que estou mostrando abaixo.

find /path/to/cool/stuff -maxdepth 4 -type d -name "*Magic Data*' \
    -exec bash -O dotglob -c '
        dir=$1
        set -- "$dir"/*
        printf "%s %d\n" "$dir" "$#"' bash {} ';'

Aqui, encontramos os diretórios como você faz, então, para cada diretório, executamos este pequeno script bash :

dir=$1
set -- "$dir"/*
printf "%s %d\n" "$dir" "$#"

Isso leva o nome do caminho do diretório a partir da linha de comando (dada por find ) e expande o padrão * glob dentro dele. Ao definir a opção dotglob shell na linha de comando do script, garantimos que também contaremos arquivos e diretórios ocultos (remova -O dotglob para não contar nomes ocultos).

Fazemos a expansão de todos os nomes como um argumento para set , que definirá os parâmetros posicionais para as entradas expandidas. O número de parâmetros posicionais está disponível como $# , que é, portanto, também a contagem de arquivos nesse diretório específico.

Relacionados:

por 16.07.2018 / 13:51
1

A partir de sua tentativa de solução, é assim que se pode realizar essa tarefa:

find /path/to/cool/stuff                        \         
        -maxdepth 4                             \         
        -type d                                 \          
        -name '*Magic Data*'                    \
        -exec sh -c '
           for d do
              printf "%s: " "$PWD/$d"
              find "$d/." -maxdepth 1 ! -name . -printf "\n" | wc -l
           done
       ' find_sh {} +

Explicação:

  • Até o ponto de find - inserir os diretórios de destino, sua receita é seguida.
  • Quando localizamos os diretórios de destino, ou seja, aqueles que têm a string "Magic Data" em algum lugar em seus nomes de base, os reunimos em um grupo {} + e os entregamos ao shell sh por meio de sua lista de argumentos: %código%
  • O argumento inicial de sh -c '...' find_sh {} + , que é o argumento zeroth sh e, como tal, pode receber qualquer nome, e aqui, neste caso, nomeamos $0 . Este é o nome que aparecerá na lista de processos.
  • O grupo de diretórios de destino entra no find_sh e forma os argumentos {} + no shell que estamos gerando.
  • Dentro desse shell que acabamos de lançar, emitimos uma nova linha para cada arquivo encontrado nos diretórios de destino, exceto ele mesmo, ou seja, $1 $2 $3 ... OTW, o nome do diretório de destino também é contado na saída wc -l.
por 22.07.2018 / 21:52
0

Você também pode usar o seguinte comando para obter o que deseja

Aqui estou usando exec para executar o sh shell, que então executa o comando dado a ele usando a opção -c . No seu caso, o comando é ls -1 | wc -l

find /path/to/cool/stuff    -maxdepth 4  -type d  -name '*Magic Data*' -print0 -exec sh -c "ls -1 {} | wc -l" \;
    
por 16.07.2018 / 14:44