En una condición Bash if, ¿cómo verificar si existen files que coincidan con una expresión de comodín simple?

Estúpidamente, había estado usando una condición como esta como parte de un guión:

if [ $(ls FOO* 2> /dev/null) ] # if files named "FOO*" were downloaded then echo "Files found" # ... process and email results else echo "Not found" # ... email warning that no files were found (against expectations) fi 

Eso funciona para cero y un file llamado FOO* , pero falla si hay más de uno . De los loggings encontré varios posts de error diferentes derivados de esto:

 [: FOO_20131107_082920: unary operator expected [: FOO_20131108_070203: binary operator expected [: too many arguments 

Mi pregunta es: ¿cuál es la forma correcta de verificar, en una condición Bash if , si existen uno o más files cuyo nombre comience con FOO ?

GNU bash, versión 4.2.25 (1) – liberación (x86_64-pc-linux-gnu)

Esto sucede porque la sustitución de su mandato para ls da como resultado espacios en blanco, y en última instancia se divide la palabra antes de pasarse a [ . Una forma less frágil sería poner los files en una matriz, y luego verificar que la matriz tenga al less un miembro.

 shopt -s nullglob files=( FOO* ) if (( ${#files[@]} )); then # there were files fi 

Esto funciona porque (( de forma pnetworkingeterminada devuelve verdadero si el valor no es igual a 0, y ${#files[@]} obtiene el número de elementos en la matriz (que será> 0 si hay files que coinciden con el glob).

También podría hacer algo como esto, siempre que nullglob no esté configurado:

 if ls FOO* >/dev/null 2>&1; then # there were files fi 

Esto solo comtesting el código de salida de ls , que será 1 si pasaste un nombre de file que no existe (el FOO* literal, si no hay coincidencias (a less que, por supuesto, seas malvado y haya un file llamado FOO* , en cuyo caso devolverá 0 :-))).

Tenga en count que ambos también coinciden con los directorys. Si realmente solo desea hacer coincidir files regulares, debe probar eso:

 for file in FOO*; do if [[ -f $file ]]; then # file found, do some stuff and break break fi done 

Las respuestas de varias líneas anteriores no se ajustaban a mi deseo de una solución de una línea y no a modificar el entorno. Aquí hay un trazador de líneas genérico que puede funcionar para usted:

 echo $(ls FOO* 2>/dev/null | wc -w) 

el / dev / null se debe a que arroja un error si no hay un file. Esto simplemente ignora ls y count la cantidad de files encontrados en function del número de "palabras" (realmente nombres de file). Puede usarlo en una simple statement if:

 if [ 0 -lt $(ls FOO* 2>/dev/null | wc -w) ]; then echo "Some FOO is there." fi 

Este enfoque tiene la flexibilidad de no solo verificar si existen files coincidentes sino también, opcionalmente, verificar cuántos files coincidentes existen (simplemente cambie 0 y / o -lt ) y luego proceda más sobre esa base.

No he verificado los files / carpetas que tienen comodines o espacios en ellos; Sospecho que el método anterior daría recuentos incorrectos en espacios en particular, que es solo un problema si se requiere un recuento exacto más allá de 0. Una solución que probé para esto es usar $(ls -l FOO* 2>/dev/null | wc -l) , que dividirá la list por líneas y, por lo tanto, debería aceptar más el espacio en blanco.

Hay otra opción, usando mayúsculas y minúsculas ,

 FILES=FOO* FILES=$(echo $FILES) case $FILES in FOO\*) echo "Not found" ;; esac 

Esto funciona como un caso que solo espera un argumento para probar.