Для петель в зш и баш

57

Я заметил, что есть два альтернативных способа построения циклов в zsh :

  1. for x (1 2 3); do echo $x; done
  2. for x in 1 2 3; do echo $x; done

Они оба печатают:

1
2
3

У меня вопрос, почему два синтаксиса? Является ли $xитерация через другой тип объекта в каждой из них?

Делает ли Bash подобное различие?

Приложение:

Почему работает следующее:

#!/bin/zsh
a=1
b=2
c=5    

d=(a b c)    
for x in $d; do print $x;done

а этот нет?

#!/bin/zsh
a=1
b=2
c=5

d=(a b c)    
# It complains with "parse error near `$d'"
for x $d; do print $x;done 
Амелио Васкес-Рейна
источник
5
для примера, который "не работает", который является стилем цикла csh , вы пропускаете скобки. for x ($d); do print $x; doneбудет работать, и он будет соответствовать первому синтаксису, который вы перечислили в начале вашего вопроса.
Тим Кеннеди
1
Это так безумие - что эти два утверждения - на самом деле не оба "работают одинаково". Я буквально не могу обдумать это! Мне нужно покурить кое-что из того, что курили эти дизайнеры оболочек », в свое время, смеется
Алекс
Осторожнее, в этой истории есть нечто большее, чем кажется на первый взгляд. Я приглашаю вас проверить мой ответ.
Jasonleonhard
Я не видел, чтобы кто-то еще упоминал об этом, но обе формы допускают пропуск do / done: for i ({0..4..2}) for j ({a..c}) echo "($i,$j)"= {0,2,4}x{a,b,c}. Точки с запятой применяются к самому внешнему циклу, а перенаправления применяются к самому внутреннему циклу, и если вам нужно это изменить, вам нужны только фигурные скобки: for i ({0..4..2}) { for j ({a..c}) echo "($i,$j)" } | cat -n= {1,...,9}*({0,2,4}x{a,b,c}). Конечно, вы можете комбинировать циклы с расширением zsh:for i ("("{0..4..2}","{a..c}")") echo $i
Джон П

Ответы:

59

Несколько форм сложных команд, таких как циклы, имеют альтернативные формы в zsh. Эти формы в основном вдохновлены оболочкой C , которая была довольно распространена, когда zsh был молодым, но теперь исчез. Эти альтернативные формы действуют точно так же, как нормальные формы, это просто другой синтаксис. Они немного короче, но менее четкие.

Стандартная форма для forкоманды for x in 1 2 3; do echo $x; done, и стандартная форма для whileкоманды while test …; do somecommand; done. Ksh, bash и zsh имеют альтернативную форму for:, for ((i = 0; i < 42; i++)); do somecommand; doneкоторая имитирует forциклы языков, таких как Pascal или C, для перечисления целых чисел. Другие экзотические формы, которые существуют в zsh, специфичны для zsh (но часто вдохновлены csh).

Жиль "ТАК - перестань быть злым"
источник
Большое спасибо @Guilles. Я все еще немного смущен, хотя. Какая форма является конкретной zsh? Кроме того, я добавил один пример в конце моего OP, где я не могу понять, как переводить между синтаксисами. Если разница только в синтаксисе, как мне исправить второй скрипт в приложении, чтобы он работал?
Амелио Васкес-Рейна
3
@intrpc Смотрите мой обновленный ответ. Что касается вашего последнего примера, он не работает, потому что вы написали, for x $dи zsh ожидает, что inили (где вы написали $d. Знаки пунктуации и зарезервированные слова не могут быть получены из раскрытия переменных, их необходимо проанализировать, прежде чем оболочка сможет начать развертывание переменных.
Жиль "ТАК - перестань быть злым"
@intrpc оба специфичны для zsh. zsh был специально разработан для поддержки синтаксиса bourne, korn и c-shell, поскольку он является гибридом всех трех.
Тим Кеннеди
1
@pseyfert Это работает, но у него нет никаких преимуществ перед формами, которые я показываю: он менее переносим, ​​чем for (( … ))форма, и использует много памяти, если 3 большой.
Жиль "ТАК - перестань быть злым"
1
@ alpha_989 В sh-подобном синтаксисе, вам нужно doпосле ));. Zsh также принимает другой синтаксис, for ((…)); COMMANDгде COMMANDесть одна команда. Вот почему он принимает for ((i = 1; i<100; i++)); ghi show $i | grep "log". Когда он видит doneпосле этого, он жалуется, потому что не doбыло конца. См. «Альтернативные формы для сложных команд» в руководстве .
Жиль "ТАК - перестань быть злым"