Boucle Bash «for» sans partie «in foo bar…»

25

Je regardais récemment un code qui m'a dérouté parce qu'il fonctionne et je ne m'y attendais pas. Le code se réduit à cet exemple

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

Lorsqu'il est exécuté avec des arguments de ligne de commande, il les imprime

$ ./test a b c
a
b
c

C'est cela, qui est (pour moi) inattendu. Pourquoi cela ne génère-t-il pas une erreur car il varn'est pas défini? Cette pratique est-elle considérée comme une «bonne pratique»?

user270650
la source

Réponses:

27

forboucles boucle sur les paramètres positionnels si aucune in value1 value2...partie n'est spécifiée dans tous les shells de type Bourne.

C'était déjà le cas dans le shell Bourne à partir de la fin des années 70, mais dans le shell Bourne, vous devez l'omettre ;(vous pouvez également l'utiliser for i do(sauf dans certaines anciennes versions de ash où vous avez besoin d'une nouvelle ligne avant le do)).

Voir À quoi sert le mot clé "do" dans Bash pour les boucles? pour plus d'informations, y compris des variantes plus surprenantes .

Faire:

for i
do
  something with "$i"
done

est une bonne pratique. Il est légèrement plus portable / fiable que son équivalent habituel:

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

pour lequel le shell Bourne, ksh88 a des problèmes dans certaines conditions (comme quand $#est 0 dans certaines versions du shell Bourne (qui ${1+"$@"}au lieu de "$@"peut contourner) ou quand $IFSne contient pas le caractère espace dans Bourne et ksh88), ou lorsque l' nounsetoption est activée et $#vaut 0 dans certaines versions de certains shells, y compris bashnouveau avec ${1+"$@"}comme solution de contournement ).

Stéphane Chazelas
la source
J'ai dû lire ceci trois fois avant que mon cerveau décide d'arrêter de modifier la boucle répétée au début
Three Diag
20

C'est le comportement par défaut, oui. Il est documenté dans le helpdu formot - clé:

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.

Ainsi, lorsque vous ne lui donnez pas de liste pour itérer, il sera par défaut itéré sur $@, le tableau de paramètres positionnels ( a, bet cdans votre exemple).

Et ce comportement est défini par POSIX donc oui, il est considéré comme une "bonne pratique" dans la mesure où cela va.

terdon
la source