Пошук порожніх каталогів UNIX


91

Мені потрібно знайти порожні каталоги для заданого списку каталогів. Деякі каталоги мають каталоги всередині нього.

Якщо внутрішні каталоги також порожні, я можу сказати, що основний каталог порожній, інакше він не порожній.

Як я можу це перевірити?

Наприклад:

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це.
Марсело Кантос,

Якщо є порожні файли , рішення не видасть повідомлення.
Ясір Арсанукаєв

3
Ясір: Я вважаю, що каталог, що містить порожній файл, не є порожнім. Чи це не буде правильним результатом?
Укко

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
Якщо ви такий нуш Баша, як я, перевірте, що тут означає -z .
OmarOthman

257

Це трохи залежить від того, що ви хочете зробити з порожніми каталогами. Я використовую наведену нижче команду, коли хочу видалити всі порожні каталоги в дереві, скажімо 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)
Доктор Персона Персона II

4
не знав про -empty, так зручно!
Раффі,

2
Однак на машині, яка не є найновішим і найкращим Linux. (EG Solaris), тоді у вас немає вигадливих функцій пошуку, таких як -empty або -delete.
Ентоні

3
На MacOS-X для майже порожніх каталогів find test -name ".DS_Store" -deleteспочатку запустіть , а потім -empty deleteкоманду. Також зверніть увагу, як до pushdбатьківського каталогу, так що це find testстає find ., але решта команд однакові.
Олі

1
@Martin Чи можете ви, будь ласка, додати визначення -depthтут, тобто Cause find для здійснення обходу в глибину, тобто каталоги відвідуються в порядку замовлення, і всі записи в каталозі будуть діяти до самого каталогу. Думаю, це тут актуально.
Лео Леопольд Герц 준영

49

Ви можете використовувати таку команду:

find . -type d -empty

1
-empty працює, лише якщо поточний каталог повністю порожній, а не якщо піддерево не містить файлів.
Марсело Кантос,

@soField Перевірена знахідка. -тип d -порожній за допомогою 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-вузлом, навіть якщо він виконує те, що хоче, що може їх заплутати. Можливо, я втрачаю суть.
Dr. Person Person 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але викликає (створює) допоміжну оболонку. Ідея від Бруно Де Фрейне та вдосконалена коментарем 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" як єдиного порожнього каталогу.


ОП просить повернути тест /

Справді. Але я прикинув, що він може прочитати сторінку пошуку людей, щоб піти далі. Сценарій, який регулює глибину на основі результатів, буде чудово працювати.
Джеймс Самнерс,

Це була найкорисніша версія для мого використання, дякую
Андреас

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.