Удалите родительский каталог (непустой), если определенный дочерний каталог пуст

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

Чтобы быть более конкретной вот, структура:

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

Подкаталоги могут или не могут содержать файл. Таким образом, я должен удалить целый каталог как '312 311' и '566532', и только '453 453' нужно оставить со всеми данными в нем, потому что он имеет файл в папке 'Recording', которая является определенным каталогом для меня.

Я видел много сообщений, но это связывается со многими определенными именами файлов. Любая справка будет очень цениться, как я должен делать много раз через неделю.

11
задан 16 September 2019 в 08:38

3 ответа

Сценарий ниже сделает точно, как Вы описываете, он:

  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. Выполните его с (полный!) каталог (содержащий Ваш subdirs, в Вашем примере) как аргумент командой:

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

Именно.

Объяснение

Питание содержания папки "A" к сценарию,

os.listdir(dr)

перечислит его подкаталоги (и файлы). Затем:

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

попытается перечислить содержание каждой из (sub) папок, которые повысят ошибку, если объект будет файлом:

except NotADirectoryError
    pass

или если папка "Recording" не существует вообще:

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

Если папка "Recording" существует и пуста, превосходящая папка удалена:

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

Править

Кроме того, согласно просьбе в комментариях, версия, которая проверит на несколько subdirs (имена).

В случае, если каталог содержит любой из перечисленных (не-пустой) subdirs, каталог сохранен. Еще это будет удалено.

Использовать

  1. Скопируйте сценарий в пустой файл, сохраните его как delete_empty.py
  2. Выполните его с (полный!) каталог (содержащий Ваш subdirs, в Вашем примере) и названия subdirs как аргументы командой:

    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))

Примечание:

Первый показ на тестовом каталоге для проверки это делает точно, что Вы хотите.

12
ответ дан 23 November 2019 в 03:53

Используя 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
11
ответ дан 23 November 2019 в 03:53

Вот более простое решение для удара:

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

Это работает потому что rmdir перестанет работать, если каталог не будет пуст, и && предотвратит rm -r от того, чтобы быть выполняемым, если rmdir успешно выполняется. Шарик */ удостоверяется, что Вы только работаете над каталогами, таким образом, другие файлы не будут затронуты.

3
ответ дан 23 November 2019 в 03:53

Другие вопросы по тегам:

Похожие вопросы: