Pensé que esto sería simple, pero está resultando más complejo de lo que esperaba.
Quiero recorrer en iteración todos los archivos de un tipo particular en un directorio, así que escribo esto:
#!/bin/bash for fname in *.zip ; do echo current file is ${fname} done 
Esto funciona siempre que haya al menos un archivo coincidente en el directorio. Sin embargo, si no hay archivos coincidentes, obtengo esto:
current file is *.zip 
Luego intenté:
#!/bin/bash FILES=`ls *.zip` for fname in "${FILES}" ; do echo current file is ${fname} done 
Si bien el cuerpo del bucle no se ejecuta cuando no hay archivos, obtengo un error de ls:
ls: *.zip: No such file or directory 
¿Cómo escribo un ¿bucle que no maneja limpiamente archivos coincidentes?
Comentarios
Responder
 En bash, puede configurar la opción nullglob para que un patrón que coincide con nada «desaparece», en lugar de tratarse como una cadena literal: 
shopt -s nullglob for fname in *.zip ; do echo "current file is ${fname}" done 
 En el script de shell POSIX, simplemente verifica que fname existe (y al mismo tiempo con [ -f ], verifique que sea un archivo normal (o enlace simbólico a un archivo normal) y no de otro tipo como directorio / FIFO / dispositivo .. .): 
for fname in *.zip; do [ -f "$fname" ] || continue printf "%s\n" "current file is $fname" done 
 Reemplace [ -f "$fname" ] con [ -e "$fname" ] || [ -L "$fname ] si desea recorrer todos los archivos (no ocultos) cuyo nombre termina en .zip independientemente de su tipo. 
 Reemplace *.zip con .*.zip .zip *.zip si también desea considerar los archivos ocultos cuyo nombre termina en .zip. 
Comentarios
-  
shopt -s nullglobno funcionó para yo en Ubuntu 17.04, pero[ -f "$fname" ] || continuefuncionó bien. -  @koppor Parece que no ' t realmente está usando 
bash. - +1 para una solución POSIX.
 
Respuesta
set ./* #set the arg array to glob results ${2+":"} [ -e "$1" ] && #if more than one result skip the stat "$1" printf "current file is %s\n" "$@" #print the whole array at once ###or### ${2+":"} [ -e "$1" ] && #same kind of test for fname #iterate singly on $fname var for array do printf "file is %s\n" "$fname" #print each $fname for each iteration done 
En un comentario aquí mencionas invocar una función …
file_fn() if [ -e "$1" ] || #check if first argument exists [ -L "$1" ] #or else if it is at least a broken link then for f #if so iterate on "$f" do : something w/ "$f" done else command <"${1-/dev/null}" #only fail w/ error if at least one arg fi file_fn * 
Respuesta
Utilice buscar
export -f myshellfunc find . -mindepth 1 -maxdepth 1 -type f -name "*.zip" -exec bash -c "myshellfunc "$0"" {} \; 
 DEBE exportar su función de shell con export -f para que esto funcione. Ahora find ejecuta bash que ejecuta su función de shell y permanece solo en el nivel de directorio actual. 
Comentarios
- Que se repite a través de subdirectorios, y quiero invocar una función bash (no un script) para las coincidencias.
 - @symcbean I ' he editado para limitar a un solo directorio y manejar funciones bash
 
Responder
En su lugar de:
FILES=`ls *.zip` 
Pruebe:
FILES=`ls * | grep *.zip` 
De esta manera, si ls falla (que hace en su caso) grep la salida fallida y regresará como una variable en blanco.
current file is <---Blank Here 
Puede agregar algo de lógica a esto para que devuelva «No Archivo encontrado «
#!/bin/bash FILES=`ls * | grep *.zip` if [[ $? == "0" ]]; then for fname in "$FILES" ; do echo current file is $fname done else echo "No Files Found" fi 
De esta manera, si el comando anterior tuvo éxito (salió con un valor 0), imprimirá el archivo actual; de lo contrario, imprimirá» No Archivos encontrados «
Comentarios
-  I thi nk es una mala idea agregar un proceso más (
grep) en lugar de intentar solucionar el problema con una herramienta mejor (find) o cambiando la configuración relevante para la solución actual (conshopt -s nullglob) -  De acuerdo con el comentario de OP ' en su publicación original, 
shopt -s nullglobno funciona. Intentéfindmientras verificaba mi respuesta y seguía fallando. Creo que por lo de exportación que dijo Dani. 
shopt -s nullglobantes de ejecutar el bucle for.FILES=ls * .zip; for fname in "${FILES}"...pero funciona como se esperaba confor fname in *.zip ; do....for file in *.zip, no`ls ...`. La sugerencia de @cuonglm ' es que*.zipse expanda a nada cuando el patrón no ' t coincide con cualquier archivo.lssin argumentos enumera el directorio actual.lsgeneralmente debe ser evitado: ¿Por qué no analizarls? ; también vea el enlace cerca de la parte superior de esa página al artículo de BashGuide ' s ParsingLs .