Shell脚本“ for”循环语法


190

我已经完成以下工作:

for i in {2..10}
do
    echo "output: $i"
done

它产生一束线output: 2output: 3,等。

但是,尝试运行以下命令:

max=10
for i in {2..$max}
do
    echo "$i"
done

产生以下内容:

output: {2..10}

如何使编译器认识到应将$ max视为数组的另一端,而不是字符串的一部分?


2
您正在使用什么系统和外壳?什么样的高飞系统具有sh或bash,却没有seq(coreutil)?
whatsisname 2009年

11
FreeBSD没有。
Nietzche-jou ​​09年

echo "$i应该echo "$i"-不会解决问题。
戴夫·贾维斯

小风格尼特:我通常看到dothen关键字在同一行forif分别。例如,for i in {2..10}; do
的付费书呆子

Answers:


232

括号扩展{x..y}在其他扩展之前执行,因此不能将其用于可变长度序列。

相反,请seq 2 $max按照用户mob所述使用该方法。

因此,以您的示例为例:

max=10
for i in `seq 2 $max`
do
    echo "$i"
done

没有充分的理由seq在for循环中使用外部命令来对数字进行计数和递增,因此建议您避免使用seq。保留该命令是为了与旧bash兼容。内置命令足够快。for (( EXP1; EXP2; EXP3 )) ...
米勒

13
@miller的for (( ... ))语法不是POSIX,这意味着例如在Alpine Linux之类的系统中,它不会开箱即用。seq做。
2016年

@Wernight不只是Alpine Linux;#!/bin/sh是Debian / Ubuntu中的Dash。
富兰克林于

72

尝试使用的算术表达式版本for

max=10
for (( i=2; i <= $max; ++i ))
do
    echo "$i"
done

这在大多数bash版本中都可用,并且还应该与Bourne shell(sh)兼容。


1
@Flow:嗯,我只是在使用#!/ bin / sh的几个系统(基于Linux和BSD的系统)上尝试过,并且工作正常。在bash下(特别是在/ bin / sh下)调用仍然有效。也许sh的版本很重要?您使用的是旧的Unix吗?
系统

8
很少有系统具有专用的sh,而是使其成为到其他外壳的链接。理想情况下,这样一个shell调用sh支持POSIX标准的功能,但默认情况下让他们的一些额外的功能通过。C样式的for循环不是POSIX功能,但sh实际的shell 可能处于模式下。
chepner 2013年

27

手动执行循环:

i = 0
最大= 10
而[$ i -lt $ max]
做
    回声“输出:$ i”
    真$((i ++))
完成

如果不必完全是POSIX,则可以使用for循环算法:

最大= 10
对于((i = 0; i <max; i ++)); 回显“输出:$ i”;完成

或在BSD系统上使用jot(1):

因为我在$(记0 10); 回显“输出:$ i”;完成

3
true $(( i++ ))并非在所有情况下都有效,因此大多数可移植性是true $((i=i+1))
流量

半冒号不应出现在“((i = 0; i <max; i ++));”中。
logan 2014年

9

有多种方法可以做到这一点。

max=10
for i in `eval "echo {2..$max}"`
do
    echo "$i"
done

7
存在安全风险,因为eval它将评估您设置的任何内容max。考虑一下max="2}; echo ha; #",然后替换echo ha为更具破坏性的内容。
chepner 2013年

6
(S)他将最大值设置为10。没有风险。
康拉德·迈尔

9

如果该seq命令在您的系统上可用:

for i in `seq 2 $max`
do
  echo "output: $i"
done

如果没有,那么用穷人的seqperl

seq=`perl -e "\$,=' ';print 2..$max"`
for i in $seq
do
  echo "output: $i"
done

注意那些引号。


我只是检查了一下;似乎并非如此。
eykanal

5

这是一种方法:重
击:

max=10
for i in $(bash -c "echo {2..${max}}"); do echo $i; done

上述击方式会为之工作kshzsh太,当bash -c被替换ksh -czsh -c分别。

注意:for i in {2..${max}}; do echo $i; done适用于zshksh


4

我们可以像C程序一样迭代循环。

#!/bin/bash
for ((i=1; i<=20; i=i+1))
do 
      echo $i
done

2

在这里,它可以在Mac OS X上运行。

它包括BSD日期的示例,以及如何增加和减少日期:

for ((i=28; i>=6 ; i--));
do
    dat=`date -v-${i}d -j "+%Y%m%d"` 
    echo $dat
done

2

好吧,由于我的系统上没有seq安装命令(Mac OS X v10.6.1(Snow Leopard)),因此我最终使用了while循环:

max=5
i=1

while [ $max -gt $i ]
do
    (stuff)
done

* 耸耸肩 *无论如何。


2
seq相对较新。我是几个月前才发现的。但是您可以使用“ for”循环!“ while”的缺点是您必须记住在循环内的某个地方增加计数器,否则向下循环。
系统暂停

1

这些都是{1..8}并且应该都是POSIX。如果将条件continue放在循环中,它们也不会中断。规范的方式:

f=
while [ $((f+=1)) -le 8 ]
do
  echo $f
done

其他方式:

g=
while
  g=${g}1
  [ ${#g} -le 8 ]
do
  echo ${#g}
done

另一个:

set --
while
  set $* .
  [ ${#} -le 8 ]
do
  echo ${#}
done

1

用:

max=10
for i in `eval echo {2..$max}`
do
    echo $i
done

您需要显式的“ eval”调用,以在变量替换后重新评估{}。

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.