Bash loop “for” sem uma parte “in foo bar…”

21

Recentemente, vi alguns códigos que me confundiram porque funcionam e eu não esperava. O código reduz para este exemplo

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

Quando executado com argumentos de linha de comando, eles são impressos

$ ./test a b c
a
b
c

É isso, isso é (para mim) inesperado. Por que isso não resulta em erro porque var é indefinido? Está usando isso considerado 'boa prática'?

    
por user270650 15.01.2018 / 17:55

2 respostas

26

for faz um loop nos parâmetros posicionais se nenhuma in value1 value2... part for especificada em todas as shells parecidas com Bourne.

Esse já era o caso no shell Bourne do final dos anos 70, embora no shell Bourne, você precisaria omitir esse ; (você também pode usar for i do (exceto em algumas versões antigas de cinzas onde você precisa de uma nova linha antes do do )).

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

Fazendo:

for i
do
  something with "$i"
done

é uma boa prática. É ligeiramente mais portátil / confiável que o normalmente equivalente:

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

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

    
por 15.01.2018 / 18:00
21

Este é o comportamento padrão, sim. Está documentado no help da palavra-chave for :

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.

Portanto, quando você não fornecer uma lista para iterar, o padrão será iterar sobre $@ , a matriz de parâmetros posicionais ( a , b e c em seu exemplo).

E esse comportamento é definido pelo POSIX então sim, é considerado "boa prática" até onde isso vai.

    
por 15.01.2018 / 17:59