Bash "for" loop sin una parte "in foo bar ..."

25

Recientemente estuve mirando un código que me confundió porque funciona y no esperaba que lo hiciera. El código se reduce a este ejemplo.

#!/bin/bash
for var;
do
  echo "$var"
done

Cuando se ejecuta con argumentos de línea de comando se imprime

$ ./test a b c
a
b
c

Es esto, eso es (para mí) inesperado. ¿Por qué esto no produce un error porque varno está definido? ¿Usar esto se considera una 'buena práctica'?

usuario270650
fuente

Respuestas:

27

forbucles bucle en los parámetros posicionales si no in value1 value2...se especifica ninguna parte en todos los shells tipo Bourne.

Ese ya era el caso en el shell Bourne de finales de los 70, aunque en el shell Bourne, tendrías que omitir eso ;(también puedes usarlo for i do(excepto en algunas versiones antiguas de ash donde necesitas una nueva línea antes del do)).

Consulte ¿Cuál es el propósito de la palabra clave "hacer" en Bash para bucles? para obtener más información, incluidas variantes más sorprendentes .

Obra:

for i
do
  something with "$i"
done

Es una buena práctica. Es un poco más portátil / confiable que el equivalente generalmente:

for i in "$@"; do
  something with "$i"
done

para el cual el shell Bourne, ksh88 tiene algunos problemas bajo ciertas condiciones (como cuando $#es 0 en algunas versiones del shell Bourne (que en ${1+"$@"}lugar de "$@"funcionar) o cuando $IFSno contiene el carácter de espacio en Bourne y ksh88), o cuando la nounsetopción está habilitada y $#es 0 en algunas versiones de algunos shells incluidos bash( nuevamente con ${1+"$@"}una solución alternativa ).

Stéphane Chazelas
fuente
Tuve que leer esto tres veces antes de que mi cerebro decidiera dejar de editar el 'ciclo' repetido al comienzo
Three Diag
20

Este es el comportamiento predeterminado, sí. Está documentado en helpla forpalabra clave:

terdon@tpad ~ $ help for
for: for NAME [in WORDS ... ] ; do COMMANDS; done
    Execute commands for each member in a list.

    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.

    Exit Status:
    Returns the status of the last command executed.

Por lo tanto, cuando usted no lo da una lista para repetir, por defecto lo iteración sobre $@el conjunto de parámetros posicionales ( a, by cen su ejemplo).

Y POSIX define este comportamiento, por lo que sí, se considera una "buena práctica" en la medida de lo posible.

terdon
fuente