Pruebe si un globo tiene coincidencias en Bash
Si quiero verificar la existencia de un solo archivo, puedo probarlo usando test -e filename
o [ -e filename ]
.
Supongamos que tengo un globo y quiero saber si existe algún archivo cuyos nombres coincidan con el globo. El globo puede coincidir con 0 archivos (en cuyo caso no necesito hacer nada), o puede coincidir con 1 o más archivos (en cuyo caso necesito hacer algo). ¿Cómo puedo comprobar si un globo tiene coincidencias? (No me importa cuántas coincidencias haya, y sería mejor si pudiera hacer esto con una if
declaración y sin bucles (simplemente porque lo encuentro más legible).
( test -e glob*
falla si el globo coincide con más de un archivo).
Solución específica de Bash :
compgen -G "<glob-pattern>"
Escapa del patrón o se expandirá previamente en coincidencias.
El estado de salida es:
- 1 por no coincidir,
- 0 para 'una o más coincidencias'
stdout
es una lista de archivos que coinciden con el glob . Creo que esta es la mejor opción en términos de concisión y minimización de posibles efectos secundarios.
Ejemplo:
if compgen -G "/tmp/someFiles*" > /dev/null; then
echo "Some files exist."
fi
La opción de shell nullglob es de hecho un bashismo.
Para evitar la necesidad de guardar y restaurar tediosamente el estado nullglob, solo lo configuraría dentro del subshell que expande el glob:
if test -n "$(shopt -s nullglob; echo glob*)"
then
echo found
else
echo not found
fi
Para una mejor portabilidad y una globalización más flexible, utilice buscar:
if test -n "$(find . -maxdepth 1 -name 'glob*' -print -quit)"
then
echo found
else
echo not found
fi
Las acciones explícitas -print -quit se utilizan para buscar en lugar de la acción implícita -print predeterminada, de modo que la búsqueda se cerrará tan pronto como encuentre el primer archivo que coincida con los criterios de búsqueda. Cuando coinciden muchos archivos, esto debería ejecutarse mucho más rápido que echo glob*
o ls glob*
y también evita la posibilidad de sobrecargar la línea de comando expandida (algunos shells tienen un límite de longitud de 4K).
Si buscar parece excesivo y la cantidad de archivos que probablemente coincidan es pequeña, use stat:
if stat -t glob* >/dev/null 2>&1
then
echo found
else
echo not found
fi
Me gusta
exists() {
[ -e "$1" ]
}
if exists glob*; then
echo found
else
echo not found
fi
Esto es legible y eficiente (a menos que haya una gran cantidad de archivos).
El principal inconveniente es que es mucho más sutil de lo que parece y, a veces, me siento obligado a añadir un comentario largo.
Si hay una coincidencia, "glob*"
el shell la expande y todas las coincidencias se pasan a exists()
, que verifica la primera e ignora el resto.
Si no hay ninguna coincidencia, "glob*"
se pasa a exists()
y se descubre que tampoco existe allí.
Editar: puede haber un falso positivo, ver comentario
#!/usr/bin/env bash
# If it is set, then an unmatched glob is swept away entirely --
# replaced with a set of zero words --
# instead of remaining in place as a single word.
shopt -s nullglob
M=(*px)
if [ "${#M[*]}" -ge 1 ]; then
echo "${#M[*]} matches."
else
echo "No such files."
fi
Si tienes configurado globfail, puedes usar este loco (que realmente no deberías)
shopt -s failglob # exit if * does not match
( : * ) && echo 0 || echo 1
o
q=( * ) && echo 0 || echo 1