Evitar errores debido al asterisco no expandido

16

En bash, a menudo uso for-loops como el siguiente

for file in *.type; do 
  sommecommand "$file"; 
done;

para realizar una operación para todos los archivos que coinciden *.type. Si no se encuentra ningún archivo con este final en los directorios de trabajo, el asterisco no se expande y, por lo general, recibo un mensaje de error que dice que algún comando no encontró el archivo. Puedo pensar de inmediato en varias formas de evitar este error. Pero agregar un condicional no parece ser muy elegante. ¿Hay una manera corta y limpia de lograr esto?

Highsciguy
fuente

Respuestas:

20

Sí, ejecuta el siguiente comando:

shopt -s nullglob

anulará la coincidencia y no se activará ningún error.

  • si desea este comportamiento por defecto, agregue el comando en su ~/.bashrc
  • si desea detectar un globo nulo en el shell POSIX, intente

    for i in *.txt; do
      [ "$i" = '*.txt' ] && [ ! -e '*.txt' ] && continue
    done

Ver http://mywiki.wooledge.org/NullGlob

Gilles Quenot
fuente
1
Tenga en cuenta que en realidad es posible tener un archivo llamado *.txt. Valdría la pena verificar si el archivo existe.
Chris Down
publicación editada en consecuencia.
Gilles Quenot
@ChrisDown Tenga en cuenta que el mismo comentario que en su respuesta se aplica aquí (con consecuencias potencialmente más graves debido a la en breaklugar de continue).
Stéphane Chazelas
6

En bash puedes usar shopt -s nullglobpara expandir a una matriz vacía si no hay coincidencias.

En shells POSIX sin nullglob, puede evitar este problema comprobando que el nombre de archivo que se pasa realmente existe teniendo [ -e "$file" ] || [ -L "$file" ] || continuecomo primera parte de su forciclo.

Chris Down
fuente
1
Tenga en cuenta que no sería estrictamente equivalente, ya [ -eque devolvería falso para archivos inaccesibles o archivos que son enlaces simbólicos a archivos inaccesibles o inexistentes.
Stéphane Chazelas
@StephaneChazelas, deja que se reconozcan los puntos sobre los enlaces simbólicos. Pero, ¿qué tienes en mente por "archivos inaccesibles"? Incluso si yo chmod 0 the_file, [ -e the_file ]todavía evalúa verdadero, por lo que debe ser otra cosa.
dubiousjim
1
Edición enviada para manejar enlaces simbólicos rotos. Espero que esté bien.
dubiousjim
2
@dubiousjim, mkdir -p x/{a,b} && chmod 444 x && echo x/* && [ -e x/a ]. x / a es inaccesible pero como x es legible x / * se expandirá.
Stéphane Chazelas
@StephaneChazelas, genial, gracias por explicarlo.
dubiousjim
4

La técnica habitual para los proyectiles que no tienen nullglobopción es

set -- [*].type *.type
case $1$2 in
  '[*].type*.type') shift 2;;
  *) shift
esac
for file do
  cmd  -- "$file"
done

El extra [*].typees para cubrir el caso donde hay un archivo llamado *.typeen el directorio actual.

Ahora, si desea incluir archivos de puntos, eso se vuelve más complicado .

Creo que esa técnica fue acuñada por Laura Fairhead en Usenet hace unos años.

Stéphane Chazelas
fuente
0

find . -name '*.type' -maxdepth 0 -exec somecommand "{}" ";"

Esto elimina el forbucle y el engrosamiento del caparazón de la ecuación por completo. findejecutará el -execcomando una vez por partida, y si no hay coincidencias, nunca se ejecutará. Las -maxdepth 0instrucciones encuentran que no se repiten en subdirectorios del argumento de ruta nombrado ( ., en este caso).

La desventaja es que involucra otra aplicación, aunque está presente en prácticamente todos los sistemas Linux (y probablemente también en la mayoría de los Unix).

un CVn
fuente