我想在 bash 中创建一个 for 循环,以 0.02 作为我尝试过的增量
for ((i=4.00;i<5.42;i+=0.02))
do
commands
done
但没有成功。
答案1
避免 shell 中出现循环。
如果你想进行算术运算,请使用awk
or bc
:
awk '
BEGIN{
for (i = 4.00; i < 5.42; i+ = 0.02)
print i
}'
或者
bc << EOF
for (i = 4.00; i < 5.42; i += 0.02) i
EOF
请注意awk
(与 相反bc
)适用于您的处理器double
浮点数表示(可能IEEE 754类型)。因此,由于这些数字是十进制数的二进制近似值,因此您可能会感到惊讶:
$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2
如果添加一个,OFMT="%.17g"
您可以看到丢失的原因0.3
:
$ gawk 'BEGIN{OFMT="%.17g"; for (i=0; i<=0.5; i+=0.1) print i}'
0
0.10000000000000001
0.20000000000000001
0.30000000000000004
0.40000000000000002
0.5
bc
具有任意精度,因此不存在此类问题。
请注意,默认情况下(除非您使用显式格式规范修改输出格式OFMT
或使用printf
显式格式规范),awk
用于%.6g
显示浮点数,因此对于超过 1,000,000 的浮点数将切换到 1e6 及以上,并截断高数字的小数部分 (100000.02将显示为 100000)。
如果您确实需要使用 shell 循环,因为例如您想为该循环的每次迭代运行特定命令,请使用具有浮点算术支持的 shell,例如zsh
,yash
或者ksh93
使用上面的一个命令生成值列表(或seq
如果可用)并循环其输出。
喜欢:
unset -v IFS # configure split+glob for default word splitting
for i in $(seq 4 0.02 5.42); do
something with "$i"
done
或者:
seq 4 0.02 5.42 | while IFS= read i; do
something with "$i"
done
除非您突破处理器浮点数的限制,否则会seq
比上面的版本更优雅地处理浮点近似引起的错误awk
。
如果您没有seq
(GNU 命令),您可以创建一个更可靠的函数,例如:
seq() { # args: first increment last
bc << EOF
for (i = $1; i <= $3; i += $2) i
EOF
}
这对于诸如 之类的事情会更有效seq 100000000001 0.000000001 100000000001.000000005
。但请注意,如果我们要将它们传递给不支持它们的命令,那么具有任意高精度的数字不会有太大帮助。
答案2
正在阅读bash
手册页给出以下信息:
for (( expr1 ; expr2 ; expr3 )) ; do list ; done
expr1
首先,根据下面算术评估中描述的规则评估算术表达式。 [...]
然后我们得到这个部分
算术评估
shell 允许在某些情况下计算算术表达式(请参阅
let
和declare
内置命令以及算术扩展)。评估以固定宽度整数完成,不检查溢出[...]
因此可以清楚地看出,不能使用for
具有非整数值的循环。
一种解决方案可能只是将所有循环组件乘以 100,以便稍后使用它们,如下所示:
for ((k=400;k<542;k+=2))
do
i=$(bc <<<"scale=2; $k / 100" ) # when k=402 you get i=4.02, etc.
...
done
如果起始值和结束值的有效数字数量相同(本例中为三个),则可以避免调用bc
for 循环的每次迭代,而是使用字符串处理来生成十进制值,
i="${k%??}.${k#?}" # POSIX; when k=402 you get i=4.02, etc.
i="${k:0:1}.${k:1}" # bash; when k=402 you get i=4.02, etc.
答案3
使用“seq” - 打印数字序列
seq 第一个增量 最后一个
for i in $(seq 4.00 0.02 5.42)
do
echo $i
done
答案4
正如其他人所建议的,您可以使用 bc:
i="4.00"
while [[ "$(bc <<< "$i < 5.42")" == "1" ]]; do
# do something with i
i="$(bc <<< "$i + 0.02")"
done