Shell 脚本使用 bash 运行,但不使用 sh。为什么以及如何解决它?

Shell 脚本使用 bash 运行,但不使用 sh。为什么以及如何解决它?

我有以下 shell 脚本,它总结了传递给它的所有参数(以空格分隔):

sum=0
for arg in "$@"; do
    (( sum += arg ))
done
echo $sum

我已将其保存为SumAll.sh.因此,它的功能应该如下:

sh SumAll.sh 2 4 6 8
20

或者

bash SumAll.sh 1 -2 3 -3
-1

两者都可以在我的本地计算机(MacBook)上运行,但是当我在 Linux 服务器中尝试相同的操作时,运行脚本 withbash可以,但 withsh不起作用。我收到以下错误:

sum: '+=': No such file or directory
sum: arg: No such file or directory

这是为什么?我该如何解决它?

答案1

算术评估(( ... ))是对所实现的标准 POSIX shell 语法的扩展bash。大多数shshell 无法理解该语法。

使用算术替换代替:sum=$(( sum + arg ))

在未实现非标准 的 shell 中(( ... )),您的(( sum += arg ))命令将被解释为嵌套子 shell,并使用sum两个参数+=和调用该命令arg

在 macOS 上,sum是一个计算文件校验和的实用程序(请参阅),并且无法找到man sum文件(这就是您收到该特定错误的原因)。+=arg

答案2

使用外壳检查

使用您的脚本的示例:

#!/bin/bash
sum=0
for arg in "$@"; do
    (( sum += arg ))
done
echo $sum

结果:

$ shellcheck myscript

Line 6:
echo $sum
     ^-- SC2086: Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
echo "$sum"

正如您所看到的,这是可行的,但是如果您像以前一样使用 sh :

#!/bin/sh
sum=0
for arg in "$@"; do
    (( sum += arg ))
done
echo $sum

结果:

$ shellcheck myscript

Line 4:
    (( sum += arg ))
    ^-- SC2039: In POSIX sh, standalone ((..)) is undefined.

Line 6:
echo $sum
     ^-- SC2086: Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
echo "$sum"

SC2039由于错误(这是本例中的第一个错误),这在这里不起作用。

虽然很明显,但您需要记住这一点sh并且bash在语法上有一些差异。所以这就是它不起作用的主要原因。 (正如 @kusalananda 在他的回答中详细说明的那样)

您还应该-x更频繁地使用 或 debug 标志,这样您就可以看到脚本失败的内容以及失败的时刻。

有关 bash 和 shell 脚本编写的更多信息和技巧,我建议:

-Bash 的非官方 Wiki

-巴什圣经

相关内容