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

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

我知道如何forbash.

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

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

此类循环的示例bash如下:

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

答案1

我在以下位置找到了有用的信息Shellcheck.net 维基, 我引用:

  1. 重击 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

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


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

#!/bin/sh
: "$((i=1))"
while [ "$((i != 10))" -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,我们分配一个常量值,因此不需要计算算术表达式。 in可以很容易地转换为表达式,而 for使用 shell 变量赋值而不是算术表达式内的变量赋值,让我们摆脱了i != 10引用的需要。test[next:


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

  • 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)}').


1 从技术上讲,该语法来自 ksh93 shell,除了 bash 之外,还可以在 zsh 中使用

答案2

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

巴什

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

POSIX

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

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

答案3

这种方法更加通用,因为您可以$在其中插入任意变量:

#!/bin/sh

for i in $(seq 1 10); do
    echo $i
done

只需确保您已seq安装实用程序,但由于它位于 中CoreUtils,因此您已安装。

相关内容