Diretórios com dois ou mais arquivos

11

Eu quero encontrar um subdiretório do diretório atual, que (que é o subdiretório) contém 2 ou mais arquivos regulares.

Não estou interessado em diretórios que contenham menos de dois arquivos, nem em diretórios que contenham apenas subdiretórios.

    
por porton 08.10.2017 / 15:09

4 respostas

12

Aqui está uma abordagem completamente diferente baseada no GNU find e uniq . Isso é muito mais rápido e amigável ao CPU do que as respostas baseadas na execução de um comando shell que conta os arquivos de cada diretório encontrado.

find . -type f -printf '%h\n' | sort | uniq -d

O comando find imprime o diretório de todos os arquivos na hierarquia e uniq exibe apenas os diretórios que aparecem pelo menos duas vezes.

    
por 08.10.2017 / 17:45
6
find . -type d \
    -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' \
    -print

Isto irá encontrar todos os nomes dentro ou fora do diretório atual e, em seguida, filtrará todos os nomes que não sejam nomes de diretórios.

Os nomes dos diretórios restantes serão dados a este pequeno script:

c=0
for n in "$1"/*; do
    [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done

[ "$c" -ge 2 ]

Este script contará o número de arquivos regulares (ignorando links simbólicos) no diretório fornecido como o primeiro argumento de linha de comando (de find ). O último comando no script é um teste para ver se a contagem era 2 ou maior. O resultado desse teste é o valor de retorno (status de saída) do script.

Se o teste for bem-sucedido, -print fará com que find imprima o caminho para o diretório.

Para também considerar arquivos ocultos (arquivos cujos nomes começam com um ponto), altere o script sh -c dizendo

for n in "$1"/*; do

para

for n in "$1"/* "$1"/.*; do

Teste:

$ tree
.
'-- test
    |-- a
    |-- dir1
    |   |-- a
    |   |-- b
    |   '-- c
    '-- dir2
        |-- dira
        |-- dirb
        |   |-- file-1
        |   '-- file-2
        '-- dirc

6 directories, 6 files

$ find . -type d -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' -print
./test/dir1
./test/dir2/dirb
    
por 08.10.2017 / 15:19
6

Com a ajuda de a resposta de Gilles em SU e seu reverso e alguma modificação, aqui o que você precisa.

find . -type d -exec sh -c 'set -- "$1"/*;X=0; 
    for args; do [ -f "$args" ] && X=$((X+1)) ;done; [ "$X" -gt 1 ] ' _ {} \; -print

Árvore de diretórios.

.
├── test
│   ├── dir1
│   │   ├── a
│   │   ├── b
│   │   └── c
│   ├── dir2
│   │   ├── dira
│   │   │   └── a file2with2multiple2line
│   │   ├── dirb
│   │   │   ├── file-1
│   │   │   └── file-2
│   │   └── dirc
│   ├── diraa
│   ├── dirbb
│   ├── dircc
│   └── x
│   └── x1
│   └── x2
└── test2
    ├── dir3
    └── dir4

Resultado:

./test
./test/dir1
./test/dir2/dirb
    
por 08.10.2017 / 15:35
3

Outra abordagem find + wc :

find path/currdir -maxdepth 1 -type d ! -empty ! -path "path/currdir" \
-exec sh -c 'count=$(find "$1" -maxdepth 1 -type f | wc -l); [ $count -ge 2 ]' _ {} \; -print
  • path/currdir - caminho para o seu diretório atual

  • -maxdepth 1 - considere apenas subpastas filho direto

  • ! -empty - ignora subpastas vazias

  • ! -path "path/currdir" - ignora o caminho do diretório atual

  • count=$(find "$1" -maxdepth 1 -type f | wc -l) - count é atribuído com o número de arquivos para cada subpasta encontrada

  • [ $count -ge 2 ] ... -print - imprime o nome / caminho da subpasta contendo 2 ou mais arquivos regulares

por 08.10.2017 / 15:38

Tags