Поиск пустых каталогов UNIX

92

Мне нужно найти пустые каталоги для данного списка каталогов. В некоторых каталогах есть каталоги внутри.

Если внутренние каталоги также пусты, я могу сказать, что основной каталог пуст, иначе он не пуст.

Как я могу это проверить?

Например:

A>A1(file1),A2 this is not empty beacuse of file1
B>B1(no file) this is empty
C>C1,C2 this is empty
soField
источник
2
Я думаю, что ответ Мартина здесь наиболее уместен. Текущий принятый ответ - это неполный псевдокод.
Лео Леопольд Герц 준영

Ответы:

34

Проверить, find <dir> -type fвыводит ли что-нибудь. Вот пример:

for dir in A B C; do
    [ -z "`find $dir -type f`" ] && echo "$dir is empty"
done
Марсело Кантос
источник
2
Нет, он не выводит подкаталоги. Вот для чего -type fэто нужно.
Марсело Кантос,
Если есть пустые файлы , ваше решение не выдаст сообщение.
Ясир Арсанукаев
4
Ясир: Я бы подумал, что каталог, содержащий пустой файл, сам по себе не будет пустым. Разве это не был бы правильный результат?
Укко
2
@akostadinov: Если я создаю каталоги и файлы, как указано OP - mkdir A B C A/A1 A/A2 B/B1 C/C1 C/C2; touch A/A1/file1- и запускаю код в моем ответе, он сообщает, что B и C пусты, как того требует OP. Так что вам нужно будет быть более конкретным, чем «это не сработает».
Марсело Кантос
1
Если вы такой же новичок в Bash, как я, проверьте, что здесь означает -z .
OmarOthman
261

Это немного зависит от того, что вы хотите делать с пустыми каталогами. Я использую приведенную ниже команду, когда хочу удалить все пустые каталоги в дереве, например testкаталог.

find test -depth -empty -delete

В приведенной выше команде следует обратить внимание на то, что она также удаляет пустые файлы , поэтому используйте параметр -type d, чтобы этого избежать.

find test -depth -type d -empty -delete

Отбросьте, -deleteчтобы увидеть совпадающие файлы и каталоги.

Если ваше определение пустого дерева каталогов состоит в том, что оно не содержит файлов, вы можете склеить что-то вместе в зависимости от того, find test -type fвозвращает ли что-нибудь.

find отличная утилита и RTFM рано и часто, чтобы действительно понять, на что она способна :-)

Мартин
источник
8
-delete подразумевает -depth (по крайней мере, для GNU findutils 4.4.2)
Dr. Person Person II
4
не знал про -empty, так удобно!
Раффи
2
Однако на машине это не последняя и лучшая версия Linux. (EG Solaris), то у вас нет никаких необычных функций поиска, таких как -empty или -delete.
Энтони
3
В MacOS-X для почти пустых каталогов find test -name ".DS_Store" -deleteсначала выполните -empty deleteкоманду , а затем выполните команду. Также обратите внимание, как pushdв родительский каталог, так что он find testстановится find ., но остальные команды остаются такими же.
Olie
1
@Martin Не могли бы вы добавить определение -depthздесь, например, Cause find для выполнения обхода в глубину, т.е. каталоги посещаются в пост-порядке, и все записи в каталоге будут действовать до самого каталога. Думаю, здесь это актуально.
Лео Леопольд Герц 준영
50

Вы можете использовать следующую команду:

find . -type d -empty
mosg
источник
1
-empty работает, только если текущий каталог полностью пуст, но не если поддерево не содержит файлов.
Марсело Кантос,
@soField Проверенная находка. -type d -empty с FreeBSD и CentOS. Работает отлично. Какая у вас ОС?
mosg
1
hp-ux, поэтому нет пустого параметра
soField
@soField Итак, вы видите, что (для всех нас) лучше размещать эти данные в начале вашего вопроса ...
mosg
2
У find также нет -empty на solaris, но есть -depth для принудительного обхода в глубину, чтобы пустые подкаталоги могли быть удалены до проверки родительского каталога на пустоту.
eirikma
26
find directory -mindepth 1 -type d -empty -delete

Эта версия показалась мне самой интересной. Если выполняется изнутри каталога , он удалит все пустые каталоги ниже (каталог считается пустым, если он содержит только пустые каталоги).

Параметр mindepth предотвращает удаление самого каталога, если он окажется пустым.

Доктор Человек Персона II
источник
2
Вы можете следить за этим, rmdir --ignore-fail-on-non-empty -p directoryчтобы избавиться и от родителей.
Пит Петерсон,
@Pete Peterson Моя команда, похоже, удаляет каталоги, которые содержат только другие пустые каталоги (это то, что OP, похоже, тоже хочет). Я отмечаю, что ваша команда обычно оставляет пользователя в каталоге с отсутствующим i-узлом, даже если он выполняет то, что хочет, что может их сбить с толку. Может, я упускаю суть.
Доктор Персона II,
23

find . -type d -empty

находит и перечисляет пустые каталоги и подкаталоги в текущем дереве. Например, результирующий список пустых каталогов и подкаталогов:

./2047
./2032
./2049
./2063
./NRCP26LUCcct1/2039
./NRCP26LUCcct1/2054
./NRCP26LUCcct1/2075
./NRCP26LUCcct1/2070

С каталогами не производится никаких операций. Они просто перечислены. У меня это работает.

user7194913
источник
16

Просто найдите пустые каталоги

Чтобы просто найти пустые каталоги (как указано в заголовке вопроса), ответ mosg правильный:

find -type d -empty

Но -emptyможет быть недоступен в очень старых findверсиях (например, в случае HP-UX ). Если это ваш случай, см. Методы, описанные в разделе ниже. Каталог пуст? .

Удалить пустые каталоги

Это немного сложно: предположим, что каталог MyDirсодержит пустые каталоги. После удаления этих пустых каталогов MyDirон станет пустым, и его также следует удалить. Поэтому я использую команду rmdirс опцией --parents(или -p), которая также удаляет родительские каталоги, когда это возможно:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} +

В более старой findверсии этот оператор +еще не поддерживается, поэтому вы можете использовать ;вместо него:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} `;`

Каталог пуст?

В большинстве этих ответов объясняется, как проверить, пуст ли каталог. Поэтому я предлагаю здесь три известных мне техники:

  1. [ $(find your/dir -prune -empty) = your/dir ]

    d=your/dir
    if [ x$(find "$d" -prune -empty) = x"$d" ]
    then
      echo "empty (directory or file)"
    else
      echo "contains files (or does not exist)"
    fi
    

    вариант:

    d=your/dir
    if [ x$(find "$d" -prune -empty -type d) = x"$d" ]
    then
      echo "empty directory"
    else
      echo "contains files (or does not exist or is not a directory)"
    fi
    

    Пояснение:

    • find -pruneаналогично find -maxdepth 0использованию меньшего количества символов
    • find -type d печатает только каталоги
    • find -empty печатает пустые каталоги и файлы

      > mkdir -v empty1 empty2 not_empty
      mkdir: created directory 'empty1'
      mkdir: created directory 'empty2'
      mkdir: created directory 'not_empty'
      > touch not_empty/file
      > find empty1 empty2 not_empty -prune -empty
      empty1
      empty2
      
  2. (( ${#files} ))

    Этот трюк на 100%, bashно вызывает (порождает) суб-оболочку. Идея принадлежит Bruno De Fraine и улучшена комментарием teambob . Я советую это, если вы используете и если ваш скрипт не обязательно должен быть переносимым.

    files=$(shopt -s nullglob dotglob; echo your/dir/*)
    if (( ${#files} ))
    then 
      echo "contains files"
    else 
      echo "empty (or does not exist or is a file)"
    fi
    

    Примечание: нет разницы между пустым каталогом и несуществующим (даже если указанный путь является файлом).

  3. [ $(ls -A your/dir) ]

    Этот трюк основан на статье nixCraft, опубликованной в 2007 году. Эндрю Тейлор ответил в 2008 году, а gr8can8dian - в 2011 году.

    if [ "$(ls -A your/dir)" ]
    then
      echo "contains files"
    else
      echo "empty (or does not exist or is a file)"
    fi
    

    или однострочная версия башизма:

    [[ "$(ls -A your/dir)" ]] && echo "contains files" || echo "empty or ..."
    

    Примечание: ls возвращается, $?=2когда каталог не существует. Но никакой разницы между файлом и пустым каталогом.

oHo
источник
rmdir -vpмне очень помогли, так как мне нужно было не просто удалить все пустые каталоги под корнем, но и проверять наличие пустых каталогов и родительских каталогов после удаления файла. В моей ситуации пустые каталоги прекрасны, если они не находятся в дереве, из которого я сейчас удаляю файл. Благодарность!
Итан
2

Эта рекурсивная функция, казалось бы, помогает:

# Bash
findempty() {
    find ${1:-.} -mindepth 1 -maxdepth 1 -type d | while read -r dir
    do
        if [[ -z "$(find "$dir" -mindepth 1 -type f)" ]] >/dev/null
        then
            findempty "$dir"
            echo "$dir"
        fi
    done
}

Учитывая этот пример структуры каталогов:

    .
    | - dir1 /
    | - dir2 /
    | `- dirB /
    | - dir3 /
    | `- dirC /
    | `- файл5
    | - dir4 /
    | | - dirD /
    | `- файл4
    `- dir5 /
        `- dirE /
            `- dir_V /

Результатом выполнения этой функции будет:

    ./dir1
    ./dir5/dirE/dir_V
    ./dir5/dirE
    ./dir5
    ./dir2/dirB
    ./dir2

который промахивается /dir4/dirD. Если вы переместите рекурсивный вызов findempty "$dir"после fi, функция включит этот каталог в свои результаты.

Приостановлено до дальнейшего уведомления.
источник
2

Как насчет rmdir *? Эта команда завершится ошибкой в ​​непустых каталогах.

Evandrix
источник
То, что я делал время от времени, для общей очистки. Также выполняются такие вещи, как rmdir */*/* */* * Хотя это не обрабатывает «точечные файлы», но в ручных ситуациях (очистка файлов данных) вы обычно не ожидаете «точечных файлов». Однако рекурсивные методы предназначены для более автоматизированной общей очистки, особенно в очень больших структурах каталогов.
Энтони,
В одном случае все было сложнее, так как мне нужно было удалить пустые каталоги, в которые включены «пустые» каталоги, которые могут содержать один файл «readme». Что-нибудь еще в каталоге, и он не был «пустым». В этом примере структура каталогов включает десятки тысяч подкаталогов.
Энтони
1

Следующая команда возвращает 1, если каталог пуст (или не существует), и 0 в противном случае (поэтому можно инвертировать код возврата с помощью !в сценарии оболочки):

find $dir -type d -prune -empty -exec false {} +
Матеуш Пиотровски
источник
0

Я создал простую структуру следующим образом:

test/
test/test2/
test/test2/test2.2/
test/test3/
test/test3/file

test/test3/fileСодержит некоторое вредный текст.

Выдача find test -emptyвозвращает " test/test2/test2.2" как единственный пустой каталог.

Джеймс Самнерс
источник
оператор также просит вернуть test / test2
На самом деле. Но я подумал, что он может прочитать справочную страницу find, чтобы пойти дальше. Скрипт, который регулирует глубину на основе результатов, будет работать нормально.
Джеймс Самнерс,
Это была самая полезная версия для моего использования, спасибо
Андреас
0

простой подход был бы,

$ [ "$(ls -A /path/to/direcory)" ] && echo "not empty" || echo "its empty"

также,

if [ "$(ls -A /path/to/direcory)" ]; then
   echo "its not empty"
else 
   echo "empty directory"
феникс24
источник
0
find . -name -type d -ls |awk '($2==0){print $11}'
Виджай
источник