Pruebe si un globo tiene coincidencias en Bash

Resuelto Ken Bloom asked hace 14 años • 21 respuestas

Si quiero verificar la existencia de un solo archivo, puedo probarlo usando test -e filenameo [ -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 ifdeclaració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).

Ken Bloom avatar May 30 '10 10:05 Ken Bloom
Aceptado

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'

stdoutes 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
Brian Chrisman avatar Dec 10 '2015 06:12 Brian Chrisman

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
flabdablet avatar Nov 24 '2010 07:11 flabdablet

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

Dan Bloch avatar Mar 20 '2013 04:03 Dan Bloch
#!/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
miku avatar May 30 '2010 03:05 miku

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
Tegra Detra avatar Jun 28 '2014 14:06 Tegra Detra