Bash цикл «for» без части «in foo bar…»

25

Недавно я смотрел на какой-то код, который смутил меня, потому что он работает, и я не ожидал этого. Код сводится к этому примеру

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

При запуске с аргументами командной строки выводит их

$ ./test a b c
a
b
c

Это то, что является (для меня) неожиданным. Почему это не приводит к ошибке, потому что varне определено? Используется ли это как «хорошая практика»?

user270650
источник

Ответы:

27

forЦиклы зацикливаются на позиционных параметрах, если ни одна in value1 value2...деталь не указана во всех оболочках, подобных Борну.

Это уже имело место в оболочке Bourne с конца 70-х годов, хотя в оболочке Bourne вам нужно было бы опустить это ;(вы также можете использовать for i do(за исключением некоторых старых версий Ash, где перед новой строкой требуется новая строка do)).

См. Какова цель ключевого слова do в Bash для циклов? для получения дополнительной информации, включая более удивительные варианты.

Выполнение:

for i
do
  something with "$i"
done

это хорошая практика. Это немного более портативный / надежный, чем обычно эквивалентный:

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

для которого оболочка Bourne, ksh88 имеет некоторые проблемы при определенных условиях (например, когда $#0 в некоторых версиях оболочки Bourne (которая ${1+"$@"}вместо "$@"может $IFSобойтись) или когда не содержит пробела в Bourne и ksh88), или когда nounsetопция включена , и $#0 в некоторых версиях некоторых оболочек , включая bash( снова ${1+"$@"}как обходной ).

Стефан Шазелас
источник
Нужно было прочитать это трижды, прежде чем мой мозг решил прекратить редактировать повторяющийся «цикл» в начале
Three Diag
20

Это поведение по умолчанию, да. Документально в helpиз 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.

Так что , если вы не даете ему список перебрать, он будет по умолчанию итерации $@, массив позиционных параметров ( a, bи cв вашем примере).

И это поведение определяется POSIX, так что да, это считается "хорошей практикой", насколько это возможно.

Тердон
источник