ZSH
Sé que la pregunta estaba marcada para bash; pero, solo como referencia, para usuarios de zsh :
Prueba de directorio no vacío
Para comprobar si foo
no está vacío:
$ for i in foo(NF) ; do ... ; done
donde, si foo
no está vacío, for
se ejecutará el código del bloque.
Prueba de directorio vacío
Para comprobar si foo
está vacío:
$ for i in foo(N/^F) ; do ... ; done
donde, si foo
está vacío, for
se ejecutará el código del bloque.
Notas
No necesitamos citar el directorio foo
anterior, pero podemos hacerlo si es necesario:
$ for i in 'some directory!'(NF) ; do ... ; done
También podemos probar más de un objeto, incluso si no es un directorio:
$ mkdir X # empty directory
$ touch f # regular file
$ for i in X(N/^F) f(N/^F) ; do echo $i ; done # echo empty directories
X
Todo lo que no sea un directorio simplemente se ignorará.
Extras
Como estamos haciendo globbing, podemos usar cualquier glob (o expansión de llaves):
$ mkdir X X1 X2 Y Y1 Y2 Z
$ touch Xf # create regular file
$ touch X1/f # directory X1 is not empty
$ touch Y1/.f # directory Y1 is not empty
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ for i in {X,Y}*(N/^F); do printf "$i "; done; echo # print empty directories
X X2 Y Y2
También podemos examinar objetos que se colocan en una matriz. Con los directorios como arriba, por ejemplo:
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ arr=(*) # place objects into array "arr"
$ for i in ${^arr}(N/^F); do printf "$i "; done; echo
X X2 Y Y2 Z
Por lo tanto, podemos probar objetos que ya pueden estar configurados en un parámetro de matriz.
Tenga en cuenta que for
, obviamente, el código del bloque se ejecuta en todos los directorios. Si esto no es deseable, simplemente puede completar un parámetro de matriz y luego operar en ese parámetro:
$ for i in *(NF) ; do full_directories+=($i) ; done
$ do_something $full_directories
Explicación
Para los usuarios de zsh existe el (F)
calificador glob (ver man zshexpn
), que coincide con directorios "llenos" (no vacíos):
$ mkdir X Y
$ touch Y/.f # Y is now not empty
$ touch f # create a regular file
$ ls -dF * # list everything in the current directory
f X/ Y/
$ ls -dF *(F) # will list only "full" directories
Y/
El calificador (F)
enumera los objetos que coinciden: es un directorio Y no está vacío. Entonces, (^F)
coincide: no es un directorio O está vacío. Por lo tanto, (^F)
solo también enumeraría archivos regulares, por ejemplo. Por lo tanto, como se explica en la zshexp
página del manual, también necesitamos el (/)
calificador glob, que enumera solo directorios:
$ mkdir X Y Z
$ touch X/f Y/.f # directories X and Y now not empty
$ for i in *(/^F) ; do echo $i ; done
Z
Por lo tanto, para verificar si un directorio determinado está vacío, puede ejecutar:
$ mkdir X
$ for i in X(/^F) ; do echo $i ; done ; echo "finished"
X
finished
y solo para estar seguro de que no se capturará un directorio que no esté vacío:
$ mkdir Y
$ touch Y/.f
$ for i in Y(/^F) ; do echo $i ; done ; echo "finished"
zsh: no matches found: Y(/^F)
finished
¡Ups! Dado Y
que no está vacío, zsh no encuentra coincidencias para (/^F)
("directorios que están vacíos") y por lo tanto escupe un mensaje de error que dice que no se encontraron coincidencias para el glob. Por lo tanto, debemos suprimir estos posibles mensajes de error con el (N)
calificador glob:
$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished
Por lo tanto, para los directorios vacíos necesitamos el calificador (N/^F)
, que se puede leer como: "no me advierta sobre fallas, directorios que no están llenos".
De manera similar, para los directorios que no están vacíos necesitamos el calificador (NF)
, que también podemos leer como: "no me adviertan sobre fallas, directorios llenos".