Відповіді:
Ось зовсім інший підхід, заснований на GNU find
та uniq
. Це набагато швидше і набагато зручніше для процесора, ніж відповіді, засновані на виконанні команди оболонки, яка підраховує файли для кожного знайденого каталогу.
find . -type f -printf '%h\n' | sort | uniq -d
find
Команда друкує каталог всіх файлів в ієрархії і uniq
відображає тільки ті каталоги , які з'являються принаймні в два рази.
-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
Це знайде всі імена в поточному каталозі або під ним, а потім відфільтрує всі імена, які не є іменами каталогів.
Решта імен каталогів буде надана цьому короткому сценарію:
c=0
for n in "$1"/*; do
[ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done
[ "$c" -ge 2 ]
Цей скрипт буде рахувати кількість регулярних файлів (пропуск символічних посилань) у каталозі, вказаний як перший аргумент командного рядка (від find
). Остання команда в скрипті - це тест, щоб перевірити, чи було число 2 або більше. Результатом цього тесту є повернене значення (статус виходу) сценарію.
Якщо тест вдався, -print
виведе find
друк шляху до каталогу.
Щоб також розглянути приховані файли (файли, імена яких починаються з крапки), змініть sh -c
сценарій, не кажучи
for n in "$1"/*; do
до
for n in "$1"/* "$1"/.*; do
Тестування:
$ 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 ]
це тест.
dash
, bash --posix
і test
всі відображатимуть повідомлення про помилку та виходять з 2 (тобто "Виникла помилка")
ksh
працює як sh
. Буде негайно внесено зміни. Дякую, що тикаєш на мене! :-)
[ -f ... ]
відміни символічні посилання. Ви повинні додати тест для їх усунення, оскільки в питанні вказано, що слід враховувати лише звичайні файли.
За допомогою відповіді Жилла про SU та його зворотному напрямку та деякій модифікації, ось що вам потрібно.
find . -type d -exec sh -c 'set -- "$1"/*;X=0;
for args; do [ -f "$args" ] && X=$((X+1)) ;done; [ "$X" -gt 1 ] ' _ {} \; -print
Дерево каталогів.
.
├── 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
Результат:
./test
./test/dir1
./test/dir2/dirb
test
і dir2
каталоги в моїй тестовій установці (див. Мою відповідь).
test/x1
і test/x2
як файли ..., $1
і $2
вони будуть каталогіми test
, і каталог буде пропущений.
Ще один 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
- шлях до поточного каталогу
-maxdepth 1
- розглядати лише прямі дочірні папки
! -empty
- ігноруйте порожні підпапки
! -path "path/currdir"
- ігнорувати поточний шлях до каталогу
count=$(find "$1" -maxdepth 1 -type f | wc -l)
- count
призначається з кількістю файлів для кожної знайденої підпапки
[ $count -ge 2 ] ... -print
- друкувати назву / шлях підпапки, що містить 2 або більше регулярних файлів
find
. У цьому випадку, оскільки GNUfind
буде маніпулювати іменами каталогів, які містять символи, які не можна друкувати в поточній локалі (наприклад, "ä" у мові C). Дивіться також unix.stackexchange.com/questions/321697/…