Usuń katalog nadrzędny (niepusty), jeśli określony katalog podrzędny jest pusty

11

Muszę zachować cały katalog, który zawiera pliki w określonym podkatalogu, ale aby usunąć pozostałe katalogi, w których podkatalog jest pusty.

Bardziej szczegółowo tutaj jest struktura:

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

Podkatalogi mogą zawierać plik lub nie. Muszę więc usunąć cały katalog, taki jak „312311” i „566532”, i należy pozostawić tylko „453453” ze wszystkimi danymi, ponieważ ma on plik w folderze „Nagrywanie”, który jest dla mnie konkretnym katalogiem.

Widziałem wiele postów, ale zawiera linki do wielu konkretnych nazw plików. Każda pomoc będzie mile widziana, ponieważ muszę to zrobić wiele razy w tygodniu.

Derek James
źródło
Czy nagrywanie jest zawsze na pierwszym poziomie w katalogu? Ponadto: czy wszystkie foldery na pierwszym poziomie znajdują się w katalogu głównym?
Jacob Vlijm
A to katalog najwyższego poziomu, w którym zawiera numerowane katalogi. A w ponumerowanych katalogach zawiera folder „Nagrywanie”, a także niektóre pliki „txt” jak np. A w „Nagrywaniu” może, ale nie musi, zawierać plików.
Derek James
Czy usuniesz obraz swojego tekstu i umieścisz rzeczywisty tekst w pytaniu? Zdjęcia tekstu są dla nas kłopotliwe. Korzystanie z rzeczywistego tekstu jest znacznie wygodniejsze, między innymi nieodłącznymi udogodnieniami.
LD James
zrobiłem to samo, o co prosiłeś James.
Derek James

Odpowiedzi:

12

Poniższy skrypt będzie działał dokładnie tak, jak opisano:

  1. wyświetla foldery w katalogu
  2. Przeszukuje każdy z folderów w poszukiwaniu folderu o nazwie „Nagrywanie”

    • Jeśli istnieje i jest pusty, usuwa folder nadrzędny
    • jeśli nie istnieje, usuwa również swój folder nadrzędny
    • pliki pierwszego poziomu wewnątrz A nie zostaną usunięte.

Na obrazku:

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

spowoduje:

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

Scenariusz

#!/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

Używać

  1. Skopiuj skrypt do pustego pliku i zapisz go jako delete_empty.py
  2. Uruchom go z katalogiem (full!) (Zawiera katalogi, A w twoim przykładzie) jako argument polecenia:

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

Otóż ​​to.

Wyjaśnienie

Przesyłanie zawartości skryptu „A” do skryptu,

os.listdir(dr)

wyświetli listę swoich podkatalogów (i plików). Następnie:

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

spróbuje wyświetlić zawartość każdego z (pod) folderów, co spowoduje błąd, jeśli element jest plikiem:

except NotADirectoryError
    pass

lub jeśli folder „Nagrywanie” w ogóle nie istnieje:

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

Jeśli folder „Nagrywanie” istnieje i jest pusty, folder nadrzędny jest usuwany:

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

EDYTOWAĆ

Dodatkowo, zgodnie z żądaniem w komentarzach, wersja, która będzie sprawdzać wiele podkatalogów (nazw).

W przypadku, gdy katalog zawiera którykolwiek z wymienionych (niepustych) podkatalogów, katalog zostaje zachowany. W przeciwnym razie zostanie usunięty.

Używać

  1. Skopiuj skrypt do pustego pliku i zapisz go jako delete_empty.py
  2. Uruchom go z katalogiem (full!) (Zawierającym twoje podkatalogi, A w twoim przykładzie) i nazwami podkatalogów jako argumentami polecenia:

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

Otóż ​​to.

Scenariusz

#!/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))

Uwaga

Najpierw uruchom katalog testowy, aby upewnić się, że działa dokładnie tak, jak chcesz.

Jacob Vlijm
źródło
ten kod naprawdę pomógł i działał, jak powiedziano. Dzięki za kod. Naprawdę pomocny.
Derek James
Załóżmy, że jeśli muszę zachować i sprawdzić dwa lub więcej folderów, jak mogę to zrobić w tym kodzie? dodanie „LUB” lub potoku ”| „gdzieś .. zasugeruj coś!
Derek James
Cześć @DerekJames, który wymaga jedynie drobnej edycji, opublikuję to popołudnie
Jacob Vlijm
@Derek, czekaj, czy należy usunąć folder nadrzędny, jeśli któryś z folderów jest pusty, czy wszystkie? Czy może być ich wiele w jednym przełożonym?
Jacob Vlijm
Załóżmy, że @Jacob, mam dwa foldery „Nagrywanie” i „Wideo”. Powinien sprawdzić oba. Jeśli którykolwiek z podfolderów zawiera plik, folder „635623” nie powinien zostać usunięty. A także możliwość dodawania kolejnych folderów, aby sprawdzić, czy da się to zrobić.
Derek James
11

Korzystanie findi xargs:

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

(usuń, gdy echotylko poczujesz się komfortowo, że identyfikuje prawidłowe katalogi). printf '%h\0Część drukuje (null zakończone) katalogu nadrzędnego - od 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
              ".".

Np .: dane

$ 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

następnie

$ 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
steeldriver
źródło
znajdź typ A d-name „Recording” -pusty -printf '% h \ 0' | xargs -0 echo rm -rf to po prostu wypisuje „rm -rf” ORAZ znajdź typ d -nazwa „Nagrywanie” -pusty -printf '% h \ 0' | xargs -0 rm -rf nie działa ... Czy robię coś złego ...
Derek James
@DerekJames musisz zastąpić A właściwym katalogiem.
Jacob Vlijm
Czy byłoby dobrze wstawić wyrażenie regularne zamiast nazwy Nagrania, ponieważ OP nadał plikom nazwy z liczbami, powiedzmy [\d]*?
George Udosen
@JacobVlijm: Zastąpiłem rzeczywisty katalog, ale nadal nie mam problemów?
Derek James
@DerekJames to dziwne! działało w moim systemie, ale być może zapomniałeś najpierw zapisać się w katalogu do katalogu? Czekaj, to nie powinno mieć znaczenia ...
Jacob Vlijm
3

Oto prostsze rozwiązanie bash:

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

Działa, ponieważ rmdirzawiedzie, jeśli katalog nie jest pusty, i &&uniemożliwi rm -rwykonanie, chyba że się rmdirpowiedzie. Glob */zapewnia, że ​​pracujesz tylko nad katalogami, więc nie będzie to miało wpływu na inne pliki.

JoL
źródło
Mądre myślenie! +1
Jacob Vlijm