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

Lin*_*eak 19 shell-script posix bourne-shell

我知道如何forbash.

如何在 POSIX shell 脚本中执行等效循环?

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

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

#!/bin/bash
for (( i=1; i != 10; i++ ))
do
    echo "$i"
done
Run Code Online (Sandbox Code Playgroud)

Lin*_*eak 17

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

  1. 重击:

     for ((init; test; next)); do foo; done
    
    Run Code Online (Sandbox Code Playgroud)
  2. POSIX:

     : "$((init))"
     while [ "$((test))" -ne 0 ]; do foo; : "$((next))"; done
    
    Run Code Online (Sandbox Code Playgroud)

但要注意这i++不是 POSIX,因此必须进行翻译,例如转换为i += 1i = i + 1

:是一个总是有成功退出代码的空命令。"$((expression))" 是一个算术展开式,作为参数传递给:. 您可以在算术扩展中分配给变量或进行算术/比较。


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

#!/bin/sh
: "$((i=1))"
while [ "$((i != 10))" -ne 0 ]
do
    echo "$i"
    : "$((i = i + 1))"
done
Run Code Online (Sandbox Code Playgroud)

虽然在这里,您可以通过以下方式使其更清晰:

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

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


除了i++-> 之外i = i + 1,还有更多非 POSIX 特定于 ksh/bash 的构造的翻译,您可能必须这样做:

  • i=1, j=2. ,算术运算符是不是真正的POSIX(以及在某些地区小数点分隔符与ksh93的冲突)。您可以将其替换为其他运算符,如+in,: "$(((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)}').


mir*_*obe 5

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

巴什

for i in {1..100}; do  
  ...  
done  
Run Code Online (Sandbox Code Playgroud)

POSIX

i=1; while [ $i -le 100 ]; do  
  ...  
  i=$(( i + 1 ))  
done
Run Code Online (Sandbox Code Playgroud)

有些人指出 seq 也是使用 seq 1 10 的选项。创建一个循环,但这取决于 os 有 seq.