Respostas:
Aqui está uma abordagem completamente diferente baseada no GNU find
e uniq
. Isso é muito mais rápido e mais amigável à CPU do que as respostas baseadas na execução de um comando shell que conta os arquivos para cada diretório encontrado.
find . -type f -printf '%h\n' | sort | uniq -d
O find
comando imprime o diretório de todos os arquivos na hierarquia e uniq
exibe apenas os diretórios que aparecem pelo menos duas vezes.
-printf '%h\0' | sort -z | uniq -zd | xargs -r0 ...
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
Isso localizará todos os nomes no diretório atual ou abaixo dele e, em seguida, filtrará todos os nomes que não sejam nomes de diretórios.
Os nomes de diretório restantes serão atribuídos a este script curto:
c=0
for n in "$1"/*; do
[ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done
[ "$c" -ge 2 ]
Esse script contará o número de arquivos regulares (pulando links simbólicos) no diretório fornecido como o primeiro argumento da linha de comando (de find
). O último comando no script é um teste para verificar se a contagem foi 2 ou superior. O resultado desse teste é o valor de retorno (status de saída) do script.
Se o teste bem sucedido, -print
irá causar find
para imprimir o caminho para o diretório.
Para também considerar arquivos ocultos (arquivos cujos nomes começam com um ponto), altere o sh -c
script 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
[ "" -ge 2 ]
é um teste válido.
dash
, bash --posix
E test
toda a exibição uma mensagem de erro e de saída com duas (ou seja, "Erro")
ksh
está sendo executado como sh
. Irá alterar imediatamente. Obrigado por me cutucar! :-)
[ -f ... ]
desreferencia links simbólicos. Você deve adicionar um teste para eliminá-los, pois a pergunta especifica que apenas os arquivos regulares devem ser contados.
Com a ajuda da resposta de Gilles no SU e seu reverso e algumas modificações, aqui está 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 file\012with\012multiple\012line
│ │ ├── dirb
│ │ │ ├── file-1
│ │ │ └── file-2
│ │ └── dirc
│ ├── diraa
│ ├── dirbb
│ ├── dircc
│ └── x
│ └── x1
│ └── x2
└── test2
├── dir3
└── dir4
Resultado:
./test
./test/dir1
./test/dir2/dirb
test
os dir2
diretórios e os arquivos na minha configuração de teste (veja minha resposta).
test/x1
e também test/x2
como arquivos ... $1
e $2
serão diretórios para test
, e o diretório será perdido.
Outra find
+ wc
abordagem:
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 diretas
! -empty
- ignorar 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
find
. Nesse caso, porque o GNUfind
irá alterar os nomes dos diretórios que possuem caracteres que não podem ser impressos no local atual (como "ä" no local C). Veja também unix.stackexchange.com/questions/321697/…