Видаліть батьківський каталог (не порожній), якщо певний дочірній каталог порожній


11

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

Щоб бути більш конкретним тут структура:

A
|
|--------312311
|       |
|       |----Recording
|       |----a.txt
|       |----b.txt
|
|
|--------453453
|       |----Recording
|                   |
|                   |-------a.mp3
|       |----a.txt
|       |----b.txt
|
|
|--------566532
|       |----Recording
|       |----a.txt
|       |----b.txt

Підкаталоги можуть містити файл, а не можуть містити його. Тому мені потрібно видалити весь каталог, як-от "312311" і "566532", і лише "453453" повинен залишитися з усіма даними в ньому, оскільки він має файл у папці "Запис", який є специфічним для мене каталогом.

Я бачив багато публікацій, але він посилається на багато конкретних імен файлів. Будь-яка допомога буде дуже вдячна, як мені потрібно робити багато разів на тиждень.


Чи запис завжди на першому рівні в каталозі? Також: чи всі папки на першому рівні всередині основного каталогу?
Яків Влійм

A - це каталог верхнього рівня, в якому він містить нумеровані каталоги. І в нумерованих каталогах вона містить папку "Запис", а також деякі файли "txt", як, наприклад, І в "Записуванні" вони можуть містити файли, а не можуть містити ..
Дерек Джеймс

Чи ви видалите малюнок свого тексту та помістите фактичний текст у своє запитання. Малюнки тексту громіздкі для нас для обробки. Використання фактичного тексту значно зручніше серед інших притаманних зручностей.
ЛД Джеймс

Я зробив те саме, про що ви просили Джеймс ..
Дерек Джеймс

Відповіді:


12

Сценарій нижче буде виконаний точно так, як ви описали:

  1. перераховує папки всередині каталогу
  2. Шукає всередині кожної з папок папку під назвою "Запис"

    • Якщо він існує і порожній, він видаляє свою вищу папку
    • якщо його не існує, він також видаляє свою верхню папку
    • Файли першого рівня всередині A не будуть видалені.

На зображенні:

A
|
|--------123456
|       |
|       |----Recording
|       |----a.txt
|       |----b.txt
|
|
|--------635623
|       |----Recording
|                   |
|                   |-------a.mp3
|       |----a.txt
|       |----b.txt
|
|
|--------123456
|       |----Recording
|       |----a.txt
|       |----b.txt
|
|--------Monkey.txt

це призведе до:

A
|
|
|--------635623
|       |----Recording
|                   |
|                   |-------a.mp3
|       |----a.txt
|       |----b.txt
|
|
|--------Monkey.txt

Сценарій

#!/usr/bin/env python3
import os
import sys
import shutil

dr = sys.argv[1]

def path(*args):
    return os.path.join(*args)

for d in os.listdir(dr):
    try:
        if not os.listdir(path(dr, d, "Recording")):
            shutil.rmtree(path(dr,d))
    except FileNotFoundError:
        shutil.rmtree(path(dr,d))
    except NotADirectoryError:
        pass

Використовувати

  1. Скопіюйте скрипт у порожній файл, збережіть його як delete_empty.py
  2. Запустіть його у каталозі (full!) (Що містить ваші підкаталоги, A у вашому прикладі) як аргумент команди:

    python3 /path/to/delete_empty.py /path/to/directory
    

Це воно.

Пояснення

Подаючи вміст папки "A" до сценарію,

os.listdir(dr)

перелічить його підкаталоги (та файли). Тоді:

if not os.listdir(path(dr, d, "Recording"))

спробує перелічити вміст кожної (під) папки, що призведе до помилки, якщо елемент є файлом:

except NotADirectoryError
    pass

або якщо папка "Запис" взагалі не існує:

FileNotFoundError
    shutil.rmtree(path(dr,d))

Якщо папка "Запис" існує і порожня, вища версія папки видаляється:

if not os.listdir(path(dr, d, "Recording")):
    shutil.rmtree(path(dr,d))

EDIT

Додатково, як вимагається в коментарях, версія, яка перевірятиме наявність кількох підкаталогів (імен).

Якщо каталог містить будь-який із перелічених (не порожніх) підкаталогів, каталог зберігається. В іншому випадку це буде видалено.

Використовувати

  1. Скопіюйте скрипт у порожній файл, збережіть його як delete_empty.py
  2. Запустіть його у каталозі (full!) (Що містить ваші підкаталоги, A у вашому прикладі) та назви підкаталів як аргументи команди:

    python3 /path/to/delete_empty.py /path/to/directory <subdir1> <subdir2> <subdir3>
    

Це воно.

Сценарій

#!/usr/bin/env python3
import shutil
import os
import sys

dr = sys.argv[1]; matches = sys.argv[2:]

def path(*args):
    return os.path.join(*args)

for d in os.listdir(dr):
    # delete directory *unless* either one of the listed subdirs has files
    keep = False
    # check for each of the listed subdirs(names)
    for name in matches:
        try:
            if os.listdir(path(dr, d, name)):
                keep = True
                break
        except NotADirectoryError:
            # if the item is not a dir, no use for other names to check
            keep = True
            break
        except FileNotFoundError:
            # if the name (subdir) does not exist, check for the next
            pass
    if not keep:
        # if there is no reason to keep --> delete
        shutil.rmtree(path(dr,d))

Примітка

Спочатку запустіть тестовий каталог, щоб переконатися, що він робить саме те, що ви хочете.


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

Припустимо, якщо мені потрібно зберегти та перевірити дві папки чи більше, як я зможу це зробити в цьому коді? додавання "АБО" або труби "| 'десь .. запропонуйте підбивати підсумки!
Дерек Джеймс

Привіт @DerekJames, що вимагає лише незначного редагування, я опублікую сьогодні вдень.
Яків Влійм

@Derek, зачекайте, чи слід видалити покращену папку, якщо будь-яка з папок порожня, або всі? Чи може бути їх декілька в одному вищому режимі?
Яків Влійм

Припустимо, @Jacob, у мене є дві папки "Запис" та "Відео". Він повинен перевірити обидва. Якщо будь-яка з підпапок містить файл, папку '635623' не слід видаляти. А також можливість додавати більше папок, щоб перевірити, чи можна це зробити ..
Дерек Джеймс

11

Використання findта xargs:

find A -type d -name 'Recording' -empty -printf '%h\0' | xargs -0 echo rm -rf

(видаліть, як echoтільки вам зручно, щоб він визначив правильні каталоги). printf '%h\0Частина друкує (нуль) батьківський каталог - від man find:

       %h     Leading directories of file's name (all but the last ele‐
              ment).  If the file name contains no slashes (since it is
              in  the  current  directory)  the %h specifier expands to
              ".".

Напр .: наведено

$ tree A
A
├── 312311
│   ├── a.txt
│   ├── b.txt
│   └── Recording
├── 453453
│   ├── a.txt
│   ├── b.txt
│   └── Recording
│       └── a.mp3
└── 566532
    ├── a.txt
    ├── b.txt
    └── Recording

6 directories, 7 files

тоді

$ find A -type d -name 'Recording' -empty -printf '%h\0' | xargs -0 rm -rf
$ 
$ tree A
A
└── 453453
    ├── a.txt
    ├── b.txt
    └── Recording
        └── a.mp3

2 directories, 3 files

знайти d-ім'я типу "Запис" -пусто -printf '% h \ 0' | xargs -0 echo rm -rf це просто друк "rm -rf" І знайти A -типу d-name "Запис" -пусто -printf '% h \ 0' | xargs -0 rm -rf не працює ... Чи я щось роблю неправильно ..
Дерек Джеймс

@DerekJames потрібно замінити A фактичним каталогом.
Яків Влійм

Було б нормально вводити регулярний вираз замість імені Запису, оскільки ОП дав імена файлів з цифрами, скажімо [\d]*?
Джордж Удосен

@JacobVlijm: Я замінив фактичний каталог, але все ще не вийшов з ладу?
Дерек Джеймс

@DerekJames це дивно! він працював у моїй системі, але ви, можливо, забули спочатку зайти в каталог? Зачекайте, це не має значення ...
Яків Влійм

3

Ось більш просте рішення bash:

for d in */; do rmdir "$d/Recording" && rm -r "$d"; done

Він працює, тому що rmdirне вдасться, якщо каталог не порожній, і &&не дозволить rm -rвиконувати його, якщо не rmdirвдасться. Глобус */гарантує, що ви працюєте лише над каталогами, тому інші файли не впливатимуть.


Розумне мислення! +1
Яків Влійм
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.