bash - script - Prueba si un globo coincide con cualquier archivo
script linux bash (17)
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 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).
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.
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.
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
No vi esta respuesta, así que pensé que la pondría allí:
set -- glob*
[ -f "$1" ] && echo "found $@"
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
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
Tengo otra solución:
if [ "$(echo glob*)" != ''glob*'' ]
Esto funciona bien para mí. ¿Hay algunos casos de esquina que extraño?
[ ls glob* 2>/dev/null | head -n 1
ls glob* 2>/dev/null | head -n 1
] && echo true
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 resto. 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
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.
#!/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
#!/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
(ls glob* &>/dev/null && echo Files found) || echo No file found
compgen -G "<glob-pattern>"
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
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.