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