web-dev-qa-db-fra.com

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

Je dois conserver tous les répertoires contenant des fichiers dans un sous-répertoire spécifique, mais supprimer tous les répertoires dans lesquels le sous-répertoire est vide.

Pour être plus précis voici l'image:

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

Les sous-répertoires peuvent ou non contenir un fichier. Il me faut donc supprimer tout le répertoire, comme "312311" et "566532" et ne laisser que "453453" avec toutes les données qu'il contient. Bcoz contient un fichier dans le dossier "Enregistrement" qui est un répertoire spécifique pour moi.

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

11
Derek James

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

  1. liste les dossiers dans un répertoire
  2. Cherche dans chaque dossier un dossier nommé "Enregistrement"

    • S'il existe et que est vide, le dossier supérieur est supprimé.
    • si n'existe pas , il supprime également son dossier supérieur
    • fichiers au premier niveau 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 le nom delete_empty.py
  2. Exécutez-le avec le répertoire (complet!) (Contenant vos sous-répertoires, A dans votre exemple) comme argument de la commande:

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

C'est ça.

Explication

Envoi du contenu du dossier "A" au script,

os.listdir(dr)

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

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

essayera de lister le contenu de chacun des (sous) dossiers, ce qui provoquera 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 que est vide, le dossier supérieur est supprimé:

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

MODIFIER

De plus, comme demandé dans les commentaires, une version qui vérifie la présence de plusieurs sous-répertoires (noms).

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

Utiliser

  1. Copiez le script dans un fichier vide, enregistrez-le sous le nom 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 en tant qu'arguments de 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 un répertoire de test pour vous assurer qu'il fait exactement ce que vous voulez.

12
Jacob Vlijm

Utiliser find et xargs:

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

(Supprimez la echo une fois que vous êtes certain qu’elle identifie les bons répertoires). La partie printf '%h\0 imprime le répertoire parent (terminé par un octet nul) - à 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

ensuite

$ 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
steeldriver

Voici une solution plus simple de bash:

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'exécution de rm -r à moins que rmdir ne réussisse. Le glob */ s'assure que vous ne travaillez que sur les répertoires afin que les autres fichiers ne soient pas affectés.

3
JoL