Risposte:
Ecco un approccio completamente diverso basato su GNU find
e uniq
. Questo è molto più veloce e molto intuitivo per la CPU rispetto alle risposte basate sull'esecuzione di un comando shell che conta i file per ogni directory trovata.
find . -type f -printf '%h\n' | sort | uniq -d
Il find
comando stampa la directory di tutti i file nella gerarchia e uniq
visualizza solo le directory che appaiono almeno due volte.
-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
Questo troverà tutti i nomi dentro o sotto la directory corrente e quindi filtrerà tutti i nomi che non sono nomi di directory.
I nomi di directory rimanenti verranno assegnati a questo breve script:
c=0
for n in "$1"/*; do
[ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done
[ "$c" -ge 2 ]
Questo script conterà il numero di file regolari (saltando i collegamenti simbolici) nella directory indicata come primo argomento della riga di comando (da find
). L'ultimo comando nello script è un test per vedere se il conteggio era 2 o maggiore. Il risultato di questo test è il valore restituito (stato di uscita) dello script.
Se il test ha esito positivo, -print
verrà find
stampato il percorso della directory.
Per considerare anche i file nascosti (file il cui nome inizia con un punto), cambia lo sh -c
script dal dire
for n in "$1"/*; do
per
for n in "$1"/* "$1"/.*; do
test:
$ 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 ]
è un test valido.
dash
, bash --posix
E test
tutte le visualizzazione di un messaggio di errore ed esce con 2 (vale a dire "l'errore è verificato un")
ksh
funziona come sh
. Si modificherà immediatamente. Grazie per avermi beccato! :-)
[ -f ... ]
dereferenze collegamenti simbolici. È necessario aggiungere un test per eliminarli poiché la domanda specifica che devono essere conteggiati solo i file regolari.
Con l'aiuto della risposta di Gilles su SU e il suo rovescio e alcune modifiche, ecco cosa ti serve.
find . -type d -exec sh -c 'set -- "$1"/*;X=0;
for args; do [ -f "$args" ] && X=$((X+1)) ;done; [ "$X" -gt 1 ] ' _ {} \; -print
Albero delle directory.
.
├── 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
Risultato:
./test
./test/dir1
./test/dir2/dirb
test
la dir2
directory nella mia configurazione di test (vedi la mia risposta).
test/x1
e anche test/x2
come file ... $1
e $2
saranno directory per test
, e la directory ci mancherà.
Un altro approccio 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
- percorso alla directory corrente
-maxdepth 1
- considera solo le sottocartelle figlio dirette
! -empty
- ignora le sottocartelle vuote
! -path "path/currdir"
- ignora il percorso della directory corrente
count=$(find "$1" -maxdepth 1 -type f | wc -l)
- count
è assegnato con il numero di file per ogni sottocartella trovata
[ $count -ge 2 ] ... -print
- stampa il nome / percorso della sottocartella contenente 2 o più file regolari
find
. In questo caso, poiché GNUfind
manipolerà i nomi delle directory che hanno caratteri che non sono stampabili nella locale corrente (come "ä" nella locale C). Vedi anche unix.stackexchange.com/questions/321697/…