Prueba si un globo coincide con cualquier archivo

Si deseo verificar la existencia de un solo archivo, puedo probarlo usando la test -e filename o [ -e filename ] .

Supongamos que tengo un globo y quiero saber si existen archivos cuyos nombres coincidan con el globo. El glob puede coincidir con 0 archivos (en cuyo caso no necesito hacer nada), o puede coincidir con 1 o más archivos (en cuyo caso tengo que hacer algo). ¿Cómo puedo probar si un glob tiene alguna coincidencia? (No me importa cuántas coincidencias haya, y sería mejor si pudiera hacer esto con una instrucción if y sin bucles (simplemente porque la encuentro más legible).

(el test -e glob* falla si el glob coincide con más de un archivo).

 compgen -G "" 

Escape del patrón o se expandirá previamente a los partidos. El estado de salida es 1 para no coincidencia, 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 minimizar los posibles efectos secundarios.

ACTUALIZACIÓN : Ejemplo de uso solicitado.

 if compgen -G "/tmp/someFiles*" > /dev/null; then echo "Some files exist." fi 

La opción de shell nullglob es de hecho un bashism.

Para evitar la necesidad de guardar y restaurar tediosamente el estado nullglob, solo lo configuré dentro de la 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 un engomado más flexible, use find:

 if test -n "$(find . -maxdepth 1 -name 'glob*' -print -quit)" then echo found else echo not found fi 

Las acciones explícitas de retención de impresión se utilizan para buscar en lugar de la acción de impresión implícita predeterminada para que el resultado se cierre tan pronto como encuentre el primer archivo que coincida con los criterios de búsqueda. Donde 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 4K de longitud).

Si la búsqueda se siente excesiva y la cantidad de archivos que probablemente coincidan es pequeña, use estadísticas:

 if stat -t glob* >/dev/null 2>&1 then echo found else echo not found fi 
 #!/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 

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 agregar un comentario largo. Si hay una coincidencia, “glob *” se expande por el shell y todas las coincidencias pasan a exists (), que verifica el primero e ignora el rest. Si no hay coincidencia, “glob *” pasa a exists () y se descubre que tampoco existe allí.

test -e tiene la desdichada advertencia de que considera que los enlaces simbólicos rotos no existen. Por lo tanto, es posible que también desee verificarlos.

 function globexists { test -e "$1" -o -L "$1" } if globexists glob*; then echo found else echo not found fi 

Tengo otra solución:

 if [ "$(echo glob*)" != 'glob*' ] 

Esto funciona bien para mí. ¿Hay algunos casos de esquina que extraño?

Basándome en la respuesta de flabdablet , para mí parece más fácil (no necesariamente el más rápido) utilizar Find, mientras se deja la expansión glob en shell, como:

 find /some/{p,long-p}ath/with/*globs* -quit &> /dev/null && echo "MATCH" 

O en if gusta:

 if find $yourGlob -quit &> /dev/null; then echo "MATCH" else echo "NOT-FOUND" fi 

Si tiene globfail configurado puede usar este loco (que realmente no debería)

 shopt -s failglob # exit if * does not match ( : * ) && echo 0 || echo 1 

o

 q=( * ) && echo 0 || echo 1 

Para simplificar la respuesta de MYYN en cierta medida, en base a su idea:

 M=(*py) if [ -e ${M[0]} ]; then echo Found else echo Not Found fi 

Esta abominación parece funcionar:

 #!/usr/bin/env bash shopt -s nullglob if [ "`echo *py`" != "" ]; then echo "Glob matched" else echo "Glob did not match" fi 

Probablemente requiera bash, no sh.

Esto funciona porque la opción nullglob hace que el glob evalúe a una cadena vacía si no hay coincidencias. Por lo tanto, cualquier salida no vacía del comando echo indica que el glob coincide con algo.

No vi esta respuesta, así que pensé que la pondría allí:

 set -- glob* [ -f "$1" ] && echo "found $@" 
 (ls glob* &>/dev/null && echo Files found) || echo No file found 
 if ls -d $glob > /dev/null 2>&1; then echo Found. else echo Not found. fi 

Tenga en cuenta que esto puede costar mucho tiempo si hay muchas coincidencias o si el acceso al archivo es lento.

 #!/bin/bash set nullglob touch /tmp/foo1 /tmp/foo2 /tmp/foo3 FOUND=0 for FILE in /tmp/foo* do FOUND=$((${FOUND} + 1)) done if [ ${FOUND} -gt 0 ]; then echo "I found ${FOUND} matches" else echo "No matches found" fi 

[ ls glob* 2>/dev/null | head -n 1 ls glob* 2>/dev/null | head -n 1 ] && echo true

En Bash, puedes glob a una matriz; si el glob no coincide, su matriz contendrá una sola entrada que no corresponde a un archivo existente:

 #!/bin/bash shellglob='*.sh' scripts=($shellglob) if [ -e "${scripts[0]}" ] then stat "${scripts[@]}" fi 

Nota: si tiene establecido nullglob , las scripts serán una matriz vacía, y deberá probar con [ "${scripts[*]}" ] o con [ "${#scripts[*]}" != 0 ] . Si está escribiendo una biblioteca que debe funcionar con o sin nullglob , querrá

 if [ "${scripts[*]}" ] && [ -e "${scripts[0]}" ] 

Una ventaja de este enfoque es que luego tiene la lista de archivos con los que desea trabajar, en lugar de tener que repetir la operación global.

Puedes hacer lo siguiente:

set – glob * si [-f “$ 1”]; luego printf “BLAH” fi

Esto funciona con sh y derivadas: ksh y bash. No crea ningún subconjunto. Los comandos $ (..) y ... crean un subconjunto: organizan un proceso y son ineficientes. Por supuesto, funciona con varios archivos, y esta solución puede ser la más rápida o la segunda más rápida.

Cuando no hay una coincidencia fpr glob * $ 1 contendrá ‘glob *’. La prueba “f” $ 1 “no será verdadera porque el archivo glob * no existe. Está bien para todos los casos

ls | grep -q "glob.*"

No es la solución más eficiente (si hay una tonelada de archivos en el directorio puede ser lenta), pero es simple, fácil de leer y también tiene la ventaja de que las expresiones regulares son más poderosas que los patrones normales de bash glob.