如果语法错误,如何使bash函数返回错误

如果语法错误,如何使bash函数返回错误,bash,error-handling,Bash,Error Handling,最近我对bash脚本做了一些更改,并在函数中出现了语法错误。我知道错误是什么(分配周围的空格:local max\u loops=4而不是local max\u loops=4) 然而,我一开始并没有发现这一点——这是一个有很多输出的长脚本,它只是输出错误,但仍在继续运行——函数返回true,因此尽管测试函数是否成功,但我没有得到任何错误 此处有一个简化版本(根据以下评论和答案更新): (我的实际函数在循环中进行填充,如果填充失败,则返回错误代码)。这只是输出: $ ./foo.sh ./foo

最近我对bash脚本做了一些更改,并在函数中出现了语法错误。我知道错误是什么(分配周围的空格:
local max\u loops=4
而不是
local max\u loops=4

然而,我一开始并没有发现这一点——这是一个有很多输出的长脚本,它只是输出错误,但仍在继续运行——函数返回true,因此尽管测试函数是否成功,但我没有得到任何错误

此处有一个简化版本(根据以下评论和答案更新):

(我的实际函数在循环中进行填充,如果填充失败,则返回错误代码)。这只是输出:

$ ./foo.sh
./foo.sh: line 1: !/bin/bash: No such file or directory
./foo.sh: line 8: max_loops: command not found
./foo.sh: line 9: [: 1: unary operator expected
Ran OK
我的问题:是否有任何通用方法可以说带有未处理错误的函数返回非零值?我尝试了
set-e
(我知道我不应该需要它两次,但为了安全起见,两次都尝试了),但似乎没有帮助

我很乐意看到整个脚本中断并停止,或者函数中断并返回非零错误。但我不想在这里看到“跑得好”


我已经修复了这里的实际错误,但我希望使脚本更加健壮。

使用
set-e

示例(t.sh):

执行:

$ bash t.sh
t.sh: line 3: x: command not found
$ echo $?
127
编辑: 您需要按如下方式更改do_magic的

do_magic
if [ $? -eq 0 ]; then
    ...

基本上,代码无法处理语法错误,因为在代码运行之前必须解析语法。我想这就是你的假设


但是,在本例中,它不是bash中的语法错误,而是由内置的
[
(或
test
)命令引起的语法错误

请注意,
[
是一个外部*命令,它或多或少是
测试
命令的别名。您可以替换:

[ 1 -lt 2 ]
作者:

比如说

这种错误只能在bash脚本的运行时检测到,并且bash脚本在默认情况下不会失败,就像任何其他失败的命令一样。好吧,只有一个例外:如果使用
set-e
,则
[
命令不会使脚本失败

*现在实现为bash内置,但它不是bash语法


如何解决

bash
为此提供了
[[
(扩展比较)功能(以及其他优势):


由于
[[
bash
语法,而不是外部命令,bash可以在代码运行之前的解析阶段处理此错误。结果是脚本根本不运行。

这不是
语法错误
,而是最常见的bash
陷阱之一

local
关键字是Bash内置的。请小心使用
local
,因为出于历史原因,此语句返回一个
成功状态
,您可能没有预料到它(Bash)。以下是一个示例:

local x=$(false) # $? == 0
vs

但是在你的例子中,这个表达式

local max_loops = 4
相当于

local max_loops
local = # error, $? == 1 - an invalid name is supplied
local 4 # error, $? == 1 
因此,您有一个返回状态为非零的命令。使用
-errexit
shell标志自动退出脚本没有帮助,因为
do\u magic
的执行上下文,请参阅

以下内容适用于
set-e

do_magic
echo "Ran OK"
请记住,如果您依赖于
set-e
,则永远不要更改上下文。即使按照

if ./do_magic.sh; then
    :
fi

足够让
set-e
magic消失了。

它会消失,除了脚本在语法错误后继续运行!如果它刚刚退出,那么我会很好的…这是失败并继续的行为我不喜欢啊,对不起,我搞错了。这不是bash语法错误,而是
测试
语法错误。让我重新措辞我的答案是…嗯,这是本地的和测试的抱怨…但是是的,可能不是一个严格的bash语法错误不,它根本不是bash错误。对于bash来说,
[
看起来就像这样
[一些字符串]
一些字符串将被
解析[
你明白我的观点吗?正如我所说,这不仅仅是测试。实际的错误在上面的变量赋值上。我从
局部max_循环中得到两个错误(第6行),从测试行中得到一个错误(第7行),就像我显示的输出一样。如果我改为
[[
那么唯一的区别就是我没有从测试行中得到错误。我仍然从变量定义(第6行)中得到错误但是测试没有结果——但最终结果是一样的:它认为函数调用成功,即使创建了错误并且循环没有运行。是的,我想知道这一点。大多数建议是避免-e,如果可以的话,但我可以尝试。但是我试过了,它对这样的函数不起作用。我在t之后直接添加了
set-e
在我的示例脚本中,他是
#!/bin/bash
。我仍然得到了错误输出,然后“运行正常”…我能想象的程序之所以没有停止的唯一原因是因为生成了子进程(带有&),这些子进程会死,但主程序不会死。看看我的示例程序。没有子进程,或者&如果
set-e
已经运行,那么
[$?-eq 0]
是毫无意义的:如果它不是0,那么将永远不会到达
If
语句。@user803422,如果
do\u magic
“显式返回错误代码”
set-e
将中止。请参阅
bash-c'f(){return 1;};set-e;f;echo“使用值$到达”“
——你永远无法接触到
。旁白:
$[]
是一个不兼容POSIX的扩展,用于向后兼容上世纪70年代的旧shell。永远不要在新代码中使用它--
i=$((i+1))
是POSIX标准化的语法……和
[
不是bash语法,因此它实际上不是一个shell语法错误。就shell而言,它的失败与调用的其他随机程序被赋予错误的命令行参数是一样的。(是的,它是作为内置的实现的,但它们在解析方面的行为与外部命令相同,
local x
x=$(false)       # $? == 1
local max_loops = 4
local max_loops
local = # error, $? == 1 - an invalid name is supplied
local 4 # error, $? == 1 
do_magic
echo "Ran OK"
if ./do_magic.sh; then
    :
fi