Bash "for" loop sem uma parte "in foo bar ..."

25

Recentemente, eu estava olhando para um código que me confundiu porque funciona e eu não esperava. O código se reduz a este exemplo

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

Quando executado com argumentos de linha de comando, os imprime

$ ./test a b c
a
b
c

É isso, que é (para mim) inesperado. Por que isso não resulta em erro porque varé indefinido? O uso desta "boa prática" é considerado?

user270650
fonte

Respostas:

27

forloops loop nos parâmetros posicionais se nenhuma in value1 value2...parte for especificada em todos os shells tipo Bourne.

Esse já era o caso no shell Bourne do final dos anos 70, embora no shell Bourne você precise omitir isso ;(você também pode usá-lo for i do(exceto em algumas versões antigas do ash em que você precisa de uma nova linha antes do do)).

Consulte Qual é o objetivo da palavra-chave "do" no Bash para loops? para mais informações, incluindo variantes mais surpreendentes .

Fazendo:

for i
do
  something with "$i"
done

é uma boa prática. É um pouco mais portátil / confiável do que o equivalente em geral:

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

para o qual o shell Bourne, o ksh88 tem alguns problemas sob algumas condições (como quando $#é 0 em algumas versões do shell Bourne (que em ${1+"$@"}vez de "$@"podem contornar) ou quando $IFSnão contém o caractere de espaço no Bourne e no ksh88), ou quando a nounsetopção está ativada e $#é 0 em algumas versões de alguns shells, incluindo bash( novamente com ${1+"$@"}uma solução alternativa ).

Stéphane Chazelas
fonte
Tinha que ler este três vezes antes que meu cérebro decidiu parar de editar o 'loop' repetido no início
Três Diag
20

Esse é o comportamento padrão, sim. Ele está documentado no helpda forpalavra-chave:

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.

Então, quando você não dar-lhe uma lista para repetir, ele será o padrão para a iteração sobre $@o conjunto de parâmetros de posição ( a, be cno seu exemplo).

E esse comportamento é definido pelo POSIX, portanto, sim, é considerado "boa prática" até o momento.

terdon
fonte