当范围由变量给定时,如何在Bash中迭代一系列数字?

我知道我可以做到这一点(在Bash文档中称为“序列表达式”):

 for i in {1..5}; do echo $i; done

这给出了:

1.2.3.4.5.

然而,如何用变量替换任意一个范围端点?这不起作用:

END=5
for i in {1..$END}; do echo $i; done

哪些打印:

{1..5}


当前回答

这适用于Bash和Korn,也可以从高到低。可能不是最快或最漂亮的,但效果足够好。也处理负片。

function num_range {
   # Return a range of whole numbers from beginning value to ending value.
   # >>> num_range start end
   # start: Whole number to start with.
   # end: Whole number to end with.
   typeset s e v
   s=${1}
   e=${2}
   if (( ${e} >= ${s} )); then
      v=${s}
      while (( ${v} <= ${e} )); do
         echo ${v}
         ((v=v+1))
      done
   elif (( ${e} < ${s} )); then
      v=${s}
      while (( ${v} >= ${e} )); do
         echo ${v}
         ((v=v-1))
      done
   fi
}

function test_num_range {
   num_range 1 3 | egrep "1|2|3" | assert_lc 3
   num_range 1 3 | head -1 | assert_eq 1
   num_range -1 1 | head -1 | assert_eq "-1"
   num_range 3 1 | egrep "1|2|3" | assert_lc 3
   num_range 3 1 | head -1 | assert_eq 3
   num_range 1 -1 | tail -1 | assert_eq "-1"
}

其他回答

这在bash中运行良好:

END=5
i=1 ; while [[ $i -le $END ]] ; do
    echo $i
    ((i = i + 1))
done
for i in $(seq 1 $END); do echo $i; done

编辑:比起其他方法,我更喜欢seq,因为我能记住它;)

POSIX方式

如果您关心可移植性,请使用POSIX标准中的示例:

i=2
end=5
while [ $i -le $end ]; do
    echo $i
    i=$(($i+1))
done

输出:

2
3
4
5

非POSIX的事物:

(())没有美元,尽管它是POSIX本身提到的常见扩展。[[.]在这里就足够了。另请参见:Bash中的单方括号和双方括号之间的区别是什么?用于((;;))seq(GNU内核){start..end},并且无法使用Bash手册中提到的变量。设i=i+1:POSIX 7 2。Shell命令语言不包含单词let,并且在bash上失败--posix 4.3.42i=$i+1的美元可能是必需的,但我不确定。POSIX 7 2.6.4算术扩展表示:如果外壳变量x包含形成有效整数常量的值,可选地包括前导加号或减号,则算术展开式“$((x))”和“$($x)”应返回相同的值。但从字面上看,这并不意味着$((x+1))会膨胀,因为x+1不是一个变量。

我知道这个问题是关于bash的,但为了记录在案,ksh93更聪明,并按预期实现:

$ ksh -c 'i=5; for x in {1..$i}; do echo "$x"; done'
1
2
3
4
5
$ ksh -c 'echo $KSH_VERSION'
Version JM 93u+ 2012-02-29

$ bash -c 'i=5; for x in {1..$i}; do echo "$x"; done'
{1..5}

这是另一种方式:

end=5
for i in $(bash -c "echo {1..${end}}"); do echo $i; done