Encontrar directorios vacíos UNIX

91

Necesito encontrar directorios vacíos para una lista determinada de directorios. Algunos directorios tienen directorios dentro.

Si los directorios internos también están vacíos, puedo decir que el directorio principal está vacío, de lo contrario no está vacío.

¿Cómo puedo probar esto?

Por ejemplo:

A>A1(file1),A2 this is not empty beacuse of file1
B>B1(no file) this is empty
C>C1,C2 this is empty
soField
fuente
2
Creo que la respuesta de Martin es la más apropiada aquí. La respuesta aceptada actual es solo un pseudocódigo incompleto.
Léo Léopold Hertz 준영

Respuestas:

34

Compruebe si find <dir> -type fproduce algo. He aquí un ejemplo:

for dir in A B C; do
    [ -z "`find $dir -type f`" ] && echo "$dir is empty"
done
Marcelo Cantos
fuente
2
No, no generará subdirectorios. Para eso -type fes.
Marcelo Cantos
Independientemente de si hay archivos vacíos , su solución no generará el mensaje.
Yasir Arsanukaev
3
Yasir: Yo pensaría que un directorio que contiene un archivo vacío no estaría vacío en sí mismo. ¿No sería ese el resultado correcto?
Ukko
2
@akostadinov: Si creo los directorios y archivos como lo indica el OP - mkdir A B C A/A1 A/A2 B/B1 C/C1 C/C2; touch A/A1/file1- y ejecuto el código en mi respuesta, informa que B y C están vacíos, como lo requiere el OP. Por lo tanto, tendrá que ser un poco más específico que "no funcionará".
Marcelo Cantos
1
Si eres un novato de Bash como yo, comprueba qué significa -z aquí .
OmarOthman
257

Depende un poco de lo que quieras hacer con los directorios vacíos. Utilizo el siguiente comando cuando deseo eliminar todos los directorios vacíos dentro de un árbol, digamos testdirectorio.

find test -depth -empty -delete

Una cosa a tener en cuenta sobre el comando anterior es que también eliminará los archivos vacíos , así que use la opción -type d para evitarlo.

find test -depth -type d -empty -delete

Suelta -deletepara ver los archivos y directorios que coinciden.

Si su definición de un árbol de directorios vacío es que no contiene archivos, entonces podrá pegar algo en función de si find test -type fdevuelve algo.

find es una gran utilidad y RTFM temprano y a menudo para comprender realmente cuánto puede hacer :-)

Martín
fuente
8
-delete implica -depth (al menos para GNU findutils 4.4.2)
Dr. Person Person II
4
no sabía -empty, tan conveniente!
Raffi
2
Sin embargo, en máquinas que no son las últimas y mejores linux. (EG Solaris), entonces no tiene funciones de búsqueda sofisticadas como -empty o -delete.
Anthony
3
En MacOS-X, para directorios casi vacíos, ejecute find test -name ".DS_Store" -deleteprimero y luego el -empty deletecomando. También tenga en cuenta, como al pushddirectorio principal, por lo que se find testconvierte find ., pero el resto de los comandos son los mismos.
Olie
1
@Martin ¿Puede agregar la definición de -depthaquí, es decir, Cause find para realizar un recorrido en profundidad primero, es decir, los directorios se visitan en orden posterior y todas las entradas de un directorio actuarán antes que el directorio mismo. Creo que es relevante aquí.
Léo Léopold Hertz 준영
49

Puede utilizar el siguiente comando:

find . -type d -empty
mosg
fuente
1
-empty solo funciona si el directorio actual está completamente vacío, no si el subárbol no contiene archivos.
Marcelo Cantos
@soField Búsqueda probada . -type d -empty con FreeBSD y CentOS. Funciona bien. ¿Cuál es tu sistema operativo?
mosg
1
hp-ux para que no haya ningún parámetro vacío
soField
@soField Entonces, ya ve, es mejor (para todos nosotros) publicar estos datos en la parte superior de su pregunta ...
mosg
2
find no tiene -empty en solaris tampoco, pero tiene -depth para hacer cumplir el recorrido de profundidad primero para que los subdirectorios vacíos puedan ser eliminados antes de que se verifique que el directorio principal esté vacío.
eirikma
26
find directory -mindepth 1 -type d -empty -delete

Esta es la versión que me pareció más interesante. Si se ejecuta desde el directorio interno , eliminará todos los directorios vacíos a continuación (un directorio se considera vacío si solo contiene directorios vacíos).

La opción mindepth evita que el directorio en sí se elimine si está vacío.

Dr. Persona Persona II
fuente
2
Puede seguir con esto rmdir --ignore-fail-on-non-empty -p directorypara deshacerse de los padres también.
Pete Peterson
@Pete Peterson Mi comando parece eliminar directorios que solo contienen otros directorios vacíos (que es lo que OP también parece querer). Observo que su comando generalmente dejará al usuario en un directorio con un i-nodo faltante incluso si logra lo que quiere, lo que puede ser confuso para ellos. Quizás me estoy perdiendo el punto.
Dr. Person Person II
23

find . -type d -empty

busca y enumera directorios y subdirectorios vacíos en el árbol actual. Por ejemplo, lista resultante de directorios y subdirectorios vacíos:

./2047
./2032
./2049
./2063
./NRCP26LUCcct1/2039
./NRCP26LUCcct1/2054
./NRCP26LUCcct1/2075
./NRCP26LUCcct1/2070

No se realiza ninguna operación en los directorios. Simplemente se enumeran. Esto funciona para mi.

usuario7194913
fuente
16

Solo encuentra directorios vacíos

Para encontrar directorios vacíos (como se especifica en el título de la pregunta), la respuesta de mosg es correcta:

find -type d -empty

Pero -emptypuede que no esté disponible en findversiones muy antiguas (este es el caso de HP-UX, por ejemplo). Si este es su caso, consulte las técnicas descritas en la sección siguiente. ¿Hay un directorio vacío? .

Eliminar directorios vacíos

Esto es un poco complicado: suponga que un directorio MyDircontiene directorios vacíos. Después de eliminar estos directorios vacíos, MyDirse convertirá en un directorio vacío y también debe eliminarse. Por lo tanto, uso el comando rmdircon la opción --parents(o -p) que también elimina los directorios principales cuando es posible:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} +

En la findversión anterior , la declaración +aún no es compatible, por lo tanto, puede usar ;en su lugar:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} `;`

¿Está vacío un directorio?

La mayoría de estas respuestas explican cómo comprobar si un directorio está vacío. Por lo tanto, proporciono aquí las tres técnicas diferentes que conozco:

  1. [ $(find your/dir -prune -empty) = your/dir ]

    d=your/dir
    if [ x$(find "$d" -prune -empty) = x"$d" ]
    then
      echo "empty (directory or file)"
    else
      echo "contains files (or does not exist)"
    fi

    una variacion:

    d=your/dir
    if [ x$(find "$d" -prune -empty -type d) = x"$d" ]
    then
      echo "empty directory"
    else
      echo "contains files (or does not exist or is not a directory)"
    fi

    Explicación:

    • find -prunees similar a find -maxdepth 0usar menos caracteres
    • find -type d imprime directorios solamente
    • find -empty imprime los directorios y archivos vacíos

      > mkdir -v empty1 empty2 not_empty
      mkdir: created directory 'empty1'
      mkdir: created directory 'empty2'
      mkdir: created directory 'not_empty'
      > touch not_empty/file
      > find empty1 empty2 not_empty -prune -empty
      empty1
      empty2
  2. (( ${#files} ))

    Este truco es 100% bashpero invoca (genera) un sub-shell. La idea es de Bruno De Fraine y mejorada por el comentario de teambob . Te aconsejo este si usas y si su script no tiene que ser portátil.

    files=$(shopt -s nullglob dotglob; echo your/dir/*)
    if (( ${#files} ))
    then 
      echo "contains files"
    else 
      echo "empty (or does not exist or is a file)"
    fi

    Nota: no hay diferencia entre un directorio vacío y uno que no existe (e incluso cuando la ruta proporcionada es un archivo).

  3. [ $(ls -A your/dir) ]

    Este truco está inspirado en el artículo de nixCraft publicado en 2007. Andrew Taylor respondió en 2008 y gr8can8dian en 2011.

    if [ "$(ls -A your/dir)" ]
    then
      echo "contains files"
    else
      echo "empty (or does not exist or is a file)"
    fi

    o la versión bashism de una línea:

    [[ "$(ls -A your/dir)" ]] && echo "contains files" || echo "empty or ..."

    Nota: ls regresa $?=2cuando el directorio no existe. Pero no hay diferencia entre un archivo y un directorio vacío.

olibre
fuente
rmdir -vpMe ayudó inmensamente, ya que necesitaba no solo eliminar todos los directorios vacíos debajo de una raíz, sino también verificar los directorios vacíos y los directorios principales después de eliminar un archivo. En mi situación, los directorios vacíos están bien siempre que no estén en el árbol del que actualmente estoy eliminando un archivo. ¡Gracias!
Ethan Hohensee
2

Esta función recursiva parecería hacer el truco:

# Bash
findempty() {
    find ${1:-.} -mindepth 1 -maxdepth 1 -type d | while read -r dir
    do
        if [[ -z "$(find "$dir" -mindepth 1 -type f)" ]] >/dev/null
        then
            findempty "$dir"
            echo "$dir"
        fi
    done
}

Dada esta estructura de directorio de ejemplo:

    .
    | - dir1 /
    | - dir2 /
    | `- dirB /
    | - dir3 /
    | `- dirC /
    | `- archivo5
    | - dir4 /
    | | - dirD /
    | `- archivo4
    `- dir5 /
        `- dirE /
            `- dir_V /

El resultado de ejecutar esa función sería:

    ./dir1
    ./dir5/dirE/dir_V
    ./dir5/dirE
    ./dir5
    ./dir2/dirB
    ./dir2

que falla /dir4/dirD. Si mueve la llamada recursiva findempty "$dir"después de fi, la función incluirá ese directorio en sus resultados.

Pausado hasta nuevo aviso.
fuente
2

¿Qué tal rmdir *? Ese comando fallará en directorios que no estén vacíos.

Evandrix
fuente
Algo que he hecho a veces, para limpieza general. También hice cosas como rmdir */*/* */* * Aunque eso no maneja 'archivos de puntos' pero luego en situaciones manuales (limpieza de archivos de datos) generalmente no espera 'archivos de puntos'. Los métodos recursivos, sin embargo, son para una limpieza general más automatizada, especialmente en estructuras de directorios muy grandes.
Anthony
En un caso fue más complicado ya que necesitaba eliminar directorios vacíos donde 'vacíos' incluía directorios que podían contener un solo archivo 'readme'. Cualquier otra cosa en el directorio y no estaba "vacío". En ese ejemplo, la estructura del directorio involucró a decenas de miles de subdirectorios.
Anthony
1

El siguiente comando devuelve 1 si un directorio está vacío (o no existe) y 0 en caso contrario (por lo que es posible invertir el código de retorno !en un script de shell):

find $dir -type d -prune -empty -exec false {} +
Mateusz Piotrowski
fuente
0

Creé una estructura simple de la siguiente manera:

test/
test/test2/
test/test2/test2.2/
test/test3/
test/test3/file

los test/test3/file contiene texto basura.

Emitir find test -emptydevoluciones " test/test2/test2.2" como el único directorio vacío.

James Sumners
fuente
la
En efecto. Pero pensé que podría leer la página de manual de búsqueda para ir más allá. Un script que ajusta las profundidades en función de los resultados funcionaría bien.
James Sumners
Esta fue la versión más útil para mi uso, gracias
Andreas
0

un enfoque simple sería,

$ [ "$(ls -A /path/to/direcory)" ] && echo "not empty" || echo "its empty"

además,

if [ "$(ls -A /path/to/direcory)" ]; then
   echo "its not empty"
else 
   echo "empty directory"
phoenix24
fuente
0
find . -name -type d -ls |awk '($2==0){print $11}'
Vijay
fuente