Supprimer le répertoire parent (non vide) si un répertoire enfant spécifique est vide

11

Je dois garder tout le répertoire qui contient des fichiers dans un sous-répertoire spécifique mais pour supprimer reste tous les répertoires dans lesquels le sous-répertoire est vide.

Pour être plus précis, voici la structure:

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

Les sous-répertoires peuvent ou non contenir un fichier. Je dois donc supprimer tout le répertoire comme '312311' et '566532' et seulement '453453' devrait rester avec toutes les données car il a un fichier dans le dossier 'Recording' qui est un répertoire spécifique pour moi.

J'ai vu de nombreux messages, mais il renvoie à de nombreux noms de fichiers spécifiques. Toute aide sera très appréciée car je dois le faire plusieurs fois par semaine.

Derek James
la source
L'enregistrement est-il toujours au premier niveau dans le répertoire? Aussi: tous les dossiers du premier niveau se trouvent-ils dans le répertoire principal?
Jacob Vlijm
A est le répertoire de niveau supérieur dans lequel il contient des répertoires numérotés. Et dans les répertoires numérotés, il contient le dossier «Enregistrement» ainsi que certains fichiers «txt» comme par exemple. Et dans 'Enregistrement', il peut ou non contenir des fichiers ..
Derek James
Voulez-vous supprimer l'image de votre texte et placer le texte réel dans votre question. Les images de texte sont lourdes à traiter pour nous. L'utilisation du texte réel est beaucoup plus pratique, entre autres commodités inhérentes.
LD James
j'ai fait la même chose que vous avez demandé James ..
Derek James

Réponses:

12

Le script ci-dessous fera exactement ce que vous décrivez, il:

  1. répertorie les dossiers dans un répertoire
  2. Recherche dans chacun des dossiers un dossier nommé "Enregistrement"

    • S'il existe et est vide, il supprime son dossier supérieur
    • s'il n'existe pas , il supprime également son dossier supérieur
    • les fichiers du premier niveau à l'intérieur de A ne seront pas supprimés.

Dans une image:

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

aura pour résultat:

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

Le scénario

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

Utiliser

  1. Copiez le script dans un fichier vide, enregistrez-le sous delete_empty.py
  2. Exécutez-le avec le répertoire (complet!) (Contenant vos sous-répertoires, A dans votre exemple) comme argument par la commande:

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

C'est ça.

Explication

Alimenter le contenu de votre dossier "A" dans le script,

os.listdir(dr)

listera ses sous-répertoires (et fichiers). Puis:

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

va essayer de lister le contenu de chacun des (sous-) dossiers, ce qui déclenchera une erreur si l'élément est un fichier:

except NotADirectoryError
    pass

ou si le dossier "Enregistrement" n'existe pas du tout:

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

Si le dossier "Enregistrement" existe et est vide, le dossier supérieur est supprimé:

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

ÉDITER

En outre, comme demandé dans les commentaires, une version qui vérifiera plusieurs sous-répertoires (noms).

Dans le cas où le répertoire contient l' un des sous-répertoires (non vides) répertoriés, le répertoire est conservé. Sinon, il sera supprimé.

Utiliser

  1. Copiez le script dans un fichier vide, enregistrez-le sous delete_empty.py
  2. Exécutez-le avec le répertoire (complet!) (Contenant vos sous-répertoires, A dans votre exemple) et les noms des sous-répertoires comme arguments par la commande:

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

C'est ça.

Le scénario

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

Remarque

Veuillez d'abord exécuter sur un répertoire de test pour vous assurer qu'il fait exactement ce que vous voulez.

Jacob Vlijm
la source
ce code a vraiment aidé et cela a fonctionné comme dit. Merci pour le code. Très utile.
Derek James
Supposons que si je dois conserver et vérifier deux dossiers ou plus, comment pourrais-je faire dans ce code? ajouter «OU» ou un tuyau »| «quelque part .. suggérer quelque chose!
Derek James
Salut @DerekJames qui ne nécessite qu'une modification mineure, je posterai cet après-midi.
Jacob Vlijm
@Derek, attendez, le dossier supérieur doit-il être supprimé si l' un des dossiers est vide, ou tous? Pourrait-il y en avoir plusieurs dans un répertoire supérieur?
Jacob Vlijm
Supposons que @Jacob, j'ai deux dossiers «Enregistrement» et «Vidéo». Il devrait vérifier les deux. Si l'un des sous-dossiers contient le fichier, le dossier «635623» ne doit pas être supprimé. Et aussi la possibilité d'ajouter plus de dossiers pour vérifier si cela peut être fait ..
Derek James
11

Utilisation de findet xargs:

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

(supprimez le echoune fois que vous êtes sûr qu'il identifie les bons répertoires). La printf '%h\0partie imprime le répertoire parent (terminé par null) - à partir de 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
              ".".

Ex.: Donné

$ 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

puis

$ 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
tournevis
la source
trouver un type d -nom «enregistrement» -empty -printf «% h \ 0» | xargs -0 echo rm -rf il s'agit simplement d'imprimer "rm -rf" ET de trouver un type -d -nom 'Recording' -empty -printf '% h \ 0' | xargs -0 rm -rf ne fonctionne pas ... Je fais quelque chose de mal ..
Derek James
@DerekJames, vous devez remplacer A par le répertoire réel.
Jacob Vlijm
Serait-il correct de mettre une expression régulière à la place du nom d' enregistrement puisque l'OP a donné des noms de fichiers avec des nombres, par exemple [\d]*?
George Udosen
@JacobVlijm: J'ai remplacé par le répertoire réel mais je ne tord toujours pas?
Derek James
@DerekJames c'est bizarre! cela a fonctionné sur mon système, mais vous avez peut-être oublié de cd dans le répertoire en premier? Attendez, cela ne devrait pas avoir d'importance ...
Jacob Vlijm
3

Voici une solution bash plus simple:

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

Cela fonctionne car rmdiréchouera si le répertoire n'est pas vide, et &&empêchera l' rm -rexécution de à moins qu'il rmdirréussisse. Le glob */s'assure que vous ne travaillez que sur les répertoires, donc les autres fichiers ne seront pas affectés.

JoL
la source
Pensée intelligente! +1
Jacob Vlijm