如何在POSIX Shell脚本中创建算术循环?


12

我知道如何在中创建算术for循环bash

如何在POSIX Shell脚本中进行等效循环?

由于有多种方法可以实现相同的目标,请随时添加您自己的答案并详细说明其工作原理。

一个这样的bash循环的示例如下:

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

@StéphaneChazelas,因为这是一段关于历史的记录,似乎是在误解的基础上,因为OP并没有暗示这是bash的事情,而只是以bash为例。看起来似乎并不相关。
terdon

Answers:


13

我在Shellcheck.net Wiki中找到了有用的信息,我引用:

  1. 重击:

    for ((init; test; next)); do foo; done
  2. POSIX:

    : "$((init))"
    while [ "$((test))" -ne 0 ]; do foo; : "$((next))"; done

尽管要注意,i++不是POSIX,所以必须将其翻译为i += 1i = i + 1


因此,可以使用如下规则将POSIX方式重写问题中的上述脚本:

#!/bin/sh
: "$((i=1))"
while [ "$((i != 0))" -ne 0 ]
do
    echo "$i"
    : "$((i = i + 1))"
done

尽管在这里,您可以通过以下方法使其更加清晰:

#!/bin/sh
i=1
while [ "$i" -ne 10 ]
do
    echo "$i"
    i=$((i + 1))
done

与中的一样init,我们正在分配一个常量值,因此我们不需要评估算术表达式。该i != 10test可以很容易地转换成一个[表达式,并next使用一个shell变量赋值,而不是一个变量赋值的算术表达式中,让我们摆脱:和需要引用。


除了i++-> 之外i = i + 1,您可能还需要进行更多非POSIX的ksh / bash特定结构的翻译:

  • i=1, j=2,算术运算符是不是真正的 POSIX(以及在某些地区小数点分隔符与ksh93的冲突)。您可以像这样将其替换为另一个运算符+: "$(((i=1) + (j=2)))"但使用起来i=1 j=2会更加清晰。
  • a[0]=1:POSIX shell中没有数组
  • i = 2**20:POSIX Shell语法中没有幂运算符。<<虽然支持,所以对于2的幂,可以使用i = 1 << 20。对于其他权力,人们可以诉诸bci=$(echo "3 ^ 20" | bc)
  • i = RANDOM % 3:不是POSIX。POSIX工具箱中最接近的是i=$(awk 'BEGIN{srand(); print int(rand() * 3)}')

2

感谢您提供有关差异的深入背景知识。使用shellcheck.net时对我有用的替代品下降如下。

重击

for i in {1..100}; do  
  ...  
done  

POSIX

i=0; while [ $i -le 100 ]; do  
  ...  
  i=$(( i + 1 ))  
done

有人指出seq也是使用seq 1 10的一种选择。创建一个循环,但是这取决于os是否具有seq。


请注意,我将i = 0放置在与while相同的行中。尽管可读性不是很好,但它只是一个衬里。这样可以确保变量i不会被脚本中定义的其他任何地方污染。
Jimmy MG Lim '18年
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.