Поиск пустых каталогов 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

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

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 предотвращает удаление самого каталога, если он окажется пустым.


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

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


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когда каталог не существует. Но никакой разницы между файлом и пустым каталогом.


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 *? Эта команда завершится ошибкой в ​​непустых каталогах.


То, что я делал время от времени, для общей очистки. Также выполняются такие вещи, как 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"

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.