Desde un script de shell, ¿cómo verifico si un directorio contiene archivos?
Algo parecido a esto
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
pero que funciona si el directorio contiene uno o varios archivos (el anterior solo funciona con exactamente 0 o 1 archivos).
Respuestas:
Las soluciones hasta ahora utilizan
ls
. Aquí hay una solución de bash:fuente
shopt -q nullglob || resetnullglob=1; shopt -s nullglob; shopt -q dotglob || resetdotglob=1; shopt -s dotglob; files=(/some/dir/*); [ "$files" ] && echo "wowzers"; [ "$resetdotglob" ] && shopt -u dotglob; [ "$resetnullglob" ] && shopt -u nullglob;
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
entonces la instrucción if debería cambiarif [ ${#files} -gt 0 ];
o tal vez simplemente olvidó el () alrededor del comando del sub-shell?files=($(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*))
Tres mejores trucos
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))
Este truco es 100%
bash
e invoca (genera) un sub-shell. La idea es de Bruno De Fraine y mejorada por el comentario de teambob .Nota: no hay diferencia entre un directorio vacío y uno que no existe (e incluso cuando la ruta proporcionada es un archivo).
Hay una alternativa similar y más detalles (y más ejemplos) en las preguntas frecuentes 'oficiales' para el canal de IRC #bash :
[ -n "$(ls -A your/dir)" ]
Este truco está inspirado en el artículo de nixCraft publicado en 2007. Agregar
2>/dev/null
para suprimir el error de salida"No such file or directory"
.Véase también la respuesta de Andrew Taylor (2008) y la respuesta de gr8can8dian (2011).
o la versión bashism de una línea:
Nota:
ls
regresa$?=2
cuando el directorio no existe. Pero no hay diferencia entre un archivo y un directorio vacío.[ -n "$(find your/dir -prune -empty)" ]
Este último truco está inspirado en la respuesta de gravstar donde
-maxdepth 0
se reemplaza por-prune
y mejorado por phils comentario 's.una variación usando
-type d
:Explicación:
find -prune
es similar afind -maxdepth 0
usar menos caracteresfind -empty
imprime los directorios y archivos vacíosfind -type d
imprime directorios solamenteNota: También puede reemplazar
[ -n "$(find your/dir -prune -empty)" ]
solo por la versión abreviada a continuación:Este último código funciona en la mayoría de los casos, pero tenga en cuenta que las rutas maliciosas pueden expresar un comando ...
fuente
[ -n "$(find "your/dir" -prune -empty)" ]
para evitar la repetición de la ruta del directorio.if [ ``ls -A your/dir`` ]
en un script, llegué a la conclusión de que funciona bien para un directorio con 0, 1 o 2 subdirectorios, pero falla para un directorio con más de 2 subdirectorios.line 17: [: 20150424-002813: unary operator expected
donde20150424-002813
estaba uno de los nombres de directorio. La cáscara usada fue/bin/bash/
. Finalmente lo cambié als "$destination" | tail -1
if [ ``ls -A my/dir`` ]
sale por errorbash: [: -A: binary operator expected
. Probado en las versiones de bash 4.1.2 y 4.2.53.-n
variante estaba en el título pero no en el párrafo siguiente). Entonces, sí, está bien.ls: cannot access '/path': No such file or directory
. ¿Hay alguna forma de suprimir este mensaje? Me gustaría fallar silenciosamente allí.¿Qué tal lo siguiente?
De esta forma no es necesario generar una lista completa del contenido del directorio. El
read
es tanto descartar la salida como hacer que la expresión se evalúe como verdadera solo cuando se lee algo (/some/dir/
es decir, se encuentra vacío porfind
).fuente
find /some/dir/ -maxdepth 0 -empty -exec echo "huzzah" \;
ls
salida y no se basa en funciones de shell no predeterminadas.-maxdepth
y no estándar-empty
.Tratar:
fuente
/bin/ls <some_dir>/* 2> /dev/null
if [! -z "$ tmp"]; luego echo Something is there fils /some/dir/*
]; luego repita "huzzah"; fi-n
lugar de! -z
(ambos son equivalentes, pero por qué no usar la forma más corta cuando existe).BigGray% if [ ! -z
ls / some / dir / * `]; luego repita "huzzah"; fi zsh: no se encontraron coincidencias: / some / dir / * `ls...
en bashfuente
¡Tenga cuidado con los directorios con muchos archivos! Podría llevar algún tiempo evaluar el
ls
comando.En mi opinión, la mejor solución es la que utiliza
fuente
fuente
¿Podrías comparar el resultado de esto?
fuente
Algunas notas de implementación:
for
bucle evita una llamada a unls
proceso externo . Todavía lee todas las entradas del directorio una vez. Esto solo se puede optimizar escribiendo un programa en C que use readdir () explícitamente.test -e
interior del bucle captura el caso de un directorio vacío, en cuyo caso a la variable_ief
se le asignaría el valor "somedir / *". Solo si ese archivo existe, la función devolverá "no vacío"test
implementación no es compatible con la-e
bandera.fuente
dotglob
no se establece -shopt -s dotglob
Esto me dice si el directorio está vacío o si no lo está, la cantidad de archivos que contiene.
fuente
ls
.Esta puede ser una respuesta muy tardía, pero aquí hay una solución que funciona. ¡Esta línea solo reconoce la existencia de archivos! No le dará un falso positivo si existen directorios.
fuente
Suponga que usted no tiene un archivo llamado
*
en/any/dir/you/check
, que debería funcionar enbash
dash
posh
busybox sh
yzsh
pero (por zsh) requierenunsetopt nomatch
.Los rendimientos deben ser comparables a cualquiera
ls
que use*
(glob), supongo que será lento en directorios con muchos nodos (mi/usr/bin
con más de 3000 archivos no fue tan lento), usará al menos la memoria suficiente para asignar todos los directorios / nombres de archivo (y más) como todos se pasan (resuelven) a la función como argumentos, algunos shell probablemente tienen límites en el número de argumentos y / o la longitud de los argumentos.Sería bueno tener una forma portátil rápida de O (1) cero recursos para verificar si un directorio está vacío.
actualizar
La versión anterior no tiene en cuenta los archivos / directorios ocultos, en caso de que se requieran más pruebas, como los trucos sh (shell POSIX)
is_empty
de Rich :Pero, en cambio, estoy pensando en algo como esto:
Alguna preocupación acerca de las diferencias de barras al final del argumento y la salida de búsqueda cuando el directorio está vacío, y las líneas nuevas al final (pero esto debería ser fácil de manejar), lamentablemente en mi
busybox
sh
programa lo que probablemente sea un error en lafind -> dd
tubería con la salida truncada aleatoriamente ( si utilicécat
la salida es siempre la misma, parece estardd
con el argumentocount
).fuente
is_empty(){ [ ! -d "${1}" ] && return 2;set -- "${1}" "${1}"/* "${1}"/.[!.]* "${1}"/..?*;[ "${*}" = "${1} ${1}/* ${1}/.[!.]* ${1}/..?*" ]; };
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: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: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:También podemos probar más de un objeto, incluso si no es un directorio:
Todo lo que no sea un directorio simplemente se ignorará.
Extras
Como estamos haciendo globbing, podemos usar cualquier glob (o expansión de llaves):
También podemos examinar objetos que se colocan en una matriz. Con los directorios como arriba, por ejemplo:
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:Explicación
Para los usuarios de zsh existe el
(F)
calificador glob (verman zshexpn
), que coincide con directorios "llenos" (no vacíos):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 lazshexp
página del manual, también necesitamos el(/)
calificador glob, que enumera solo directorios:Por lo tanto, para verificar si un directorio determinado está vacío, puede ejecutar:
y solo para estar seguro de que no se capturará un directorio que no esté vacío:
¡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: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".fuente
Me sorprende que no se haya mencionado la guía de wooledge sobre directorios vacíos . Esta guía, y todo Wooledge realmente, es una lectura obligada para preguntas de tipo shell.
De nota de esa página:
fuente
Pequeña variación de la respuesta de Bruno :
Esto funciona para mi
fuente
Tomando una pista (o varias) de la respuesta de olibre, me gusta una función Bash:
Porque aunque crea una subcapa, es lo más parecido a una solución O (1) que puedo imaginar y darle un nombre lo hace legible. Entonces puedo escribir
En cuanto a O (1), hay casos atípicos: si un directorio grande ha tenido todas o todas las entradas eliminadas, excepto la última, es posible que "find" tenga que leer todo para determinar si está vacío. Creo que el rendimiento esperado es O (1) pero el peor de los casos es lineal en el tamaño del directorio. No he medido esto.
fuente
Hasta ahora no he visto una respuesta que use grep, lo que creo que daría una respuesta más simple (¡sin demasiados símbolos extraños!). Así es como comprobaría si existe algún archivo en el directorio usando bourne shell:
esto devuelve el número de archivos en un directorio:
puede completar la ruta del directorio donde está escrito el directorio. La primera mitad de la tubería asegura que el primer carácter de salida sea "-" para cada archivo. egrep luego cuenta el número de líneas que comienzan con ese símbolo usando expresiones regulares. ahora todo lo que tiene que hacer es almacenar el número que obtiene y compararlo usando comillas inversas como:
x es una variable de su elección.
fuente
Mezclando ciruelas y últimas respuestas, llegué a
que funciona para caminos con espacios también
fuente
Respuesta simple con bash :
fuente
Yo iría por
find
:Esto verifica el resultado de buscar solo archivos en el directorio, sin pasar por los subdirectorios. Luego verifica la salida usando la
-z
opción tomada deman test
:Vea algunos resultados:
Directorio vacío:
Solo dirs en él:
Un archivo en el directorio:
Un archivo en un subdirectorio:
fuente
Con alguna solución, pude encontrar una forma sencilla de averiguar si hay archivos en un directorio. Esto se puede extender con más comandos grep para verificar específicamente archivos .xml o .txt, etc. Ej:
ls /some/dir | grep xml | wc -l | grep -w "0"
fuente
fuente
nullglob
, porque entonces ells
comando tendrá éxito.para probar un directorio de destino específico
fuente
Prueba con el comando find. Especifique el directorio codificado o como argumento. Luego inicie buscar para buscar todos los archivos dentro del directorio. Compruebe si el retorno de la búsqueda es nulo. Hacer eco de los datos de encontrar
fuente
No me gustan las
ls - A
soluciones publicadas. Lo más probable es que desee probar si el directorio está vacío porque no desea eliminarlo. Lo siguiente hace eso. Sin embargo, si solo desea registrar un archivo vacío, seguramente eliminarlo y recrearlo es más rápido que enumerar archivos posiblemente infinitos.Esto debería funcionar...
fuente
${target}/..
.Funciona bien para mí esto (cuando existe dir):
Con verificación completa:
fuente