For zsh和bash中的循环


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
真是太疯狂了 -那两个声明-确实都不能“相同地工作”。我真的无法解决这个问题!我需要抽烟那些贝壳设计者正在抽烟的东西,回想起来,哈哈。
亚历克斯·格雷2014年

小心一点,这个故事比最初出现的更多。我邀请您检查我的答案。
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
John P

Answers:


58

复杂的命令的几种形式(例如循环)在zsh中具有备用形式。这些形式主要受C外壳的启发,C外壳在zsh很小的时候就很常见,但是现在已经消失了。这些替代形式的行为与普通形式完全相同,只是语法不同。它们稍短一些,但不太清楚。

为标准形式for的命令是for x in 1 2 3; do echo $x; done,和用于标准形式while的命令是while test …; do somecommand; done。Ksh,bash和zsh具有另一种形式的forfor ((i = 0; i < 42; i++)); do somecommand; done,它模仿forPascal或C之类的语言循环来枚举整数。zsh中存在的其他奇特形式是特定于zsh的(但通常受csh的启发)。


非常感谢@Guilles。我还是有点困惑。具体使用哪种形式zsh?另外,我在OP的末尾添加了一个示例,无法弄清楚如何在语法之间进行转换。如果区别只是语法,我应该如何修正附录中的第二个脚本以使其起作用?
Amelio Vazquez-Reina

3
@intrpc请参阅我的最新答案。至于你的最后一个例子,这是行不通的,因为你写的for x $d和预期的zsh要么in或者(,你写的$d。标点符号和保留字不能来自变量扩展,因此必须先解析它们,然后外壳程序才能从变量扩展开始。
吉尔斯

@intrpc都是zsh特有的。zsh专为同时支持bourne,korn和c-shell语法而设计,因为它是所有这三种的混合。
肯尼迪

1
@pseyfert它可以工作,但是与我展示的表单相比没有任何优势:它不如for (( … ))表单轻便,并且如果3大则占用大量内存。
吉尔斯

1
@ alpha_989在类似sh的语法中,需要doafter ));。Zsh还接受另一种语法for ((…)); COMMAND,其中COMMAND单个命令。这就是为什么它接受for ((i = 1; i<100; i++)); ghi show $i | grep "log"。当它看到done此事后,便抱怨说,因为没有do结局。请参见手册中的“复杂命令的替代形式”
吉尔斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.