Eliminar el directorio principal (no vacío) si un directorio secundario específico está vacío

11

Tengo que mantener todo el directorio que contiene los archivos en un subdirectorio específico, pero para eliminar el resto, todos los directorios en los que el subdirectorio esté vacío.

Para ser más específicos, aquí está la estructura:

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

Los subdirectorios pueden o no contener un archivo. Por lo tanto, necesito eliminar todo el directorio como '312311' y '566532' y solo '453453' debería quedar con todos los datos en él porque tiene un archivo en la carpeta 'Grabación' que es un directorio específico para mí.

Vi muchas publicaciones pero enlaza con muchos nombres de archivos específicos. Cualquier ayuda será muy apreciada, ya que tengo que hacerlo muchas veces en una semana.

Derek James
fuente
¿La grabación siempre está en el primer nivel del directorio? Además: ¿están todas las carpetas en el primer nivel dentro del directorio principal?
Jacob Vlijm
A es el directorio de nivel superior en el que contiene directorios numerados. Y en los directorios numerados contiene la carpeta 'Grabación', así como algunos archivos 'txt' como en eg. Y en 'Grabación' puede o no contener archivos ...
Derek James
¿Eliminará la imagen de su texto y colocará el texto real en su pregunta? Las imágenes de texto son engorrosas para que las procesemos. Usar el texto real es sustancialmente más conveniente, entre otras comodidades inherentes.
LD James
Hice lo mismo que le preguntó por James ..
Derek James

Respuestas:

12

El siguiente script hará exactamente lo que usted describe:

  1. enumera las carpetas dentro de un directorio
  2. Busca dentro de cada una de las carpetas una carpeta llamada "Grabación"

    • Si existe y está vacío, elimina su carpeta superior
    • si no existe, también elimina su carpeta superior
    • los archivos en el primer nivel dentro de A no se eliminarán.

En una imagen:

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

resultará en:

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

La secuencia de comandos

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

Usar

  1. Copie el script en un archivo vacío, guárdelo como delete_empty.py
  2. Ejecútelo con el directorio (completo) (que contiene sus subdirectorios, A en su ejemplo) como argumento mediante el comando:

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

Eso es.

Explicación

Alimentando el contenido de su carpeta "A" al script,

os.listdir(dr)

enumerará sus subdirectorios (y archivos). Entonces:

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

intentará enumerar el contenido de cada una de las (sub) carpetas, lo que generará un error si el elemento es un archivo:

except NotADirectoryError
    pass

o si la carpeta "Grabación" no existe en absoluto:

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

Si la carpeta "Grabación" existe y está vacía, se elimina la carpeta superior:

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

EDITAR

Además, como se solicitó en los comentarios, una versión que verificará múltiples subdirecciones (nombres).

En caso de que el directorio contenga alguno de los subdirectorios enumerados (no vacíos), el directorio se conserva. De lo contrario, se eliminará.

Usar

  1. Copie el script en un archivo vacío, guárdelo como delete_empty.py
  2. Ejecútelo con el directorio (completo) (que contiene sus subdirecciones, A en su ejemplo) y los nombres de subdirecciones como argumentos mediante el comando:

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

Eso es.

La secuencia de comandos

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

Nota

Primero ejecute en un directorio de prueba para asegurarse de que hace exactamente lo que desea.

Jacob Vlijm
fuente
Este código realmente ayudó y funcionó como se dijo. Gracias por el codigo. De mucha ayuda.
Derek James
Supongamos que si necesito mantener y verificar dos carpetas o más, ¿cómo podré hacerlo en este código? agregando 'OR' o tubería '| 'en alguna parte ... ¡sugiera algo!
Derek James
Hola @DerekJames que solo requiere una edición menor, publicaré esta tarde.
Jacob Vlijm
@Derek, espere, ¿debería eliminarse la carpeta superior si alguna de las carpetas está vacía o todas? ¿Podría haber varios de ellos en un directorio superior?
Jacob Vlijm
Supongamos que @Jacob, tengo dos carpetas 'Grabación' y 'Video'. Debería verificar ambos. Si alguna de las subcarpetas contiene el archivo, la carpeta '635623' no debe eliminarse. Y también la capacidad de agregar más carpetas para verificar si se puede hacer ..
Derek James
11

Usando findy xargs:

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

(elimine echouna vez que se sienta cómodo de que está identificando los directorios correctos). La printf '%h\0parte imprime el directorio padre (terminado en nulo) desde 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
              ".".

Ej .: dado

$ 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

entonces

$ 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
conductor de acero
fuente
encuentre A -type d -name 'Grabando' -empty -printf '% h \ 0' | xargs -0 echo rm -rf esto es solo imprimir "rm -rf" Y encontrar un tipo d -nombre 'Grabación' -empty -printf '% h \ 0' | xargs -0 rm -rf no funciona ... ¿Estoy haciendo algo mal?
Derek James
@DerekJames necesita reemplazar A con el directorio real.
Jacob Vlijm
¿Estaría bien poner una expresión regular en lugar del nombre de la grabación ya que el OP dio nombres de archivos con números, por ejemplo [\d]*?
George Udosen
@JacobVlijm: ¿Reemplacé con el directorio real pero aún no me estoy arrugando?
Derek James
@DerekJames eso es extraño! funcionó en mi sistema, pero es posible que haya olvidado ingresar el CD primero en el directorio. Espera, eso no debería importar ...
Jacob Vlijm
3

Aquí hay una solución bash más simple:

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

Funciona porque rmdirfallará si el directorio no está vacío y &&evitará que rm -rse ejecute a menos que rmdirtenga éxito. El glob */se asegura de que solo esté trabajando en los directorios, por lo que otros archivos no se verán afectados.

JoL
fuente
¡Pensamiento inteligente! +1
Jacob Vlijm