Bash:源代码脚本中出现错误时停止
在要执行的shell脚本中,我可以使用Bash:源代码脚本中出现错误时停止,bash,shell,Bash,Shell,在要执行的shell脚本中,我可以使用set-e中止错误 但是,在源代码脚本中,如果稍后的命令以错误状态退出,则使用set-e将终止原始shell source set_e.sh ./exit_1.sh # shell dies 一个简单的解决方案是在脚本末尾设置+e,但如果使用,这会破坏父脚本的set-e(如果将来有人包装我的脚本,这很可能发生) 如何在源代码脚本中获得错误中止功能?您可以通过set-o检测是否在源代码脚本的开头设置了errexit选项,并在源代码脚本的结尾恢复其原始值。您可
set-e
中止错误
但是,在源代码脚本中,如果稍后的命令以错误状态退出,则使用set-e
将终止原始shell
source set_e.sh
./exit_1.sh
# shell dies
一个简单的解决方案是在脚本末尾设置+e,但如果使用,这会破坏父脚本的set-e
(如果将来有人包装我的脚本,这很可能发生)
如何在源代码脚本中获得错误中止功能?您可以通过
set-o
检测是否在源代码脚本的开头设置了errexit选项,并在源代码脚本的结尾恢复其原始值。您可以检查set-e
是否已启用,然后有条件地设置它:
[[ $- == *e* ]] && state=-e || state=+e
set -e
yourcode
set "$state"
然而,请注意,set-e
是有缺陷的,脚本永远不应该依赖它来确保正确性。例如,如果有人在if
语句中生成您的脚本,set-e
可能不再正常工作:
echo '
set -e
ls file.that.doesnt.exist
echo "Success"
' > yourscript
set -e
if ! source yourscript
then
echo "Initialization failed"
fi
echo "Done"
然后,bash 4.3.30中的yourscript
中出现故障时,set-e
将不再中止:
ls: cannot access file.that.doesnt.exist: No such file or directory
Success
Done
虽然它将退出bash 2、3和4.2中的整个脚本:
ls: cannot access file.that.doesnt.exist: No such file or directory
将
set-e
更改为返回0
(或者选择您喜欢的整数而不是0
)。您可以将其视为将源文件视为一个函数。例如:
$ cat myreturn.sh
#!/bin/bash
let i=0
while test "$i" -lt 10; do
echo "i $i"
if test "$i" -gt 5 ; then
return 5
fi
sleep 1
((i+=1))
done
return 4
$ ( . myreturn.sh )
i 0
i 1
i 2
i 3
i 4
i 5
i 6
$ echo $?
5
这是不可能的。但是,如果需要,您可以选择使用子shell:
(
set -e
source another.sh
)
只有调用脚本的环境永远不能被被调用的脚本改变
注意:使用换行符分隔两个命令可能很重要,并且不要使用分号。好吧,问题不是很清楚:原始作者在截获源代码脚本中的错误后想要什么,但是,作为解决方案的入口点,以下内容就足够了: 您可以在ERR上设置陷阱,并在源代码脚本中处理错误。下面是两个场景:一个是源代码脚本使用“set-e”,另一个是源代码脚本不使用“set-e” 主脚本正在使用定义的“set-e”调用辅助脚本,并捕获错误:
[galaxy => ~]$ cat primary.sh
#!/bin/sh
set -e
echo 'Primary script'
trap 'echo "Got an error from the secondary script"' ERR
source secondary.sh
trap - ERR
echo 'Primary script exiting'
[galaxy => ~]$ cat secondary.sh
#!/bin/sh
echo 'Secondary script'
set -e
echo 'Secondary script generating an error'
false
echo 'Secondary script - should not be reached'
[galaxy => ~]$ ./primary.sh
Primary script
Secondary script
Secondary script generating an error
Got an error from the secondary script
[galaxy => ~]$
[galaxy => ~]$ cat primary.sh
#!/bin/sh
set -e
echo 'Primary script'
trap 'echo "Got an error from the secondary script"' ERR
source secondary.sh
trap - ERR
echo 'Primary script exiting'
[galaxy => ~]$ cat secondary.sh
#!/bin/sh
echo 'Secondary script'
echo 'Secondary script generating an error'
false
echo 'Secondary script - should not be reached if sourced by primary.sh'
[galaxy => ~]$ ./primary.sh
Primary script
Secondary script
Secondary script generating an error
Got an error from the secondary script
[galaxy => ~]$
[galaxy => ~]$ cat primary.sh
#!/bin/sh
echo 'Primary script'
i=0
while [ $i = 0 ]; do
i=1
trap 'echo "Got an error from the secondary script"; break' ERR
source secondary.sh
done
trap - ERR
echo 'Primary script exiting'
[galaxy => ~]$ cat secondary.sh
#!/bin/sh
echo 'Secondary script'
echo 'Secondary script generating an error'
false
echo 'Secondary script - should not be reached if sourced by primary.sh'
[galaxy => ~]$ ./primary.sh
Primary script
Secondary script
Secondary script generating an error
Got an error from the secondary script
Primary script exiting
[galaxy => ~]$
主脚本正在调用没有“set-e”的辅助脚本,并捕获错误:
[galaxy => ~]$ cat primary.sh
#!/bin/sh
set -e
echo 'Primary script'
trap 'echo "Got an error from the secondary script"' ERR
source secondary.sh
trap - ERR
echo 'Primary script exiting'
[galaxy => ~]$ cat secondary.sh
#!/bin/sh
echo 'Secondary script'
set -e
echo 'Secondary script generating an error'
false
echo 'Secondary script - should not be reached'
[galaxy => ~]$ ./primary.sh
Primary script
Secondary script
Secondary script generating an error
Got an error from the secondary script
[galaxy => ~]$
[galaxy => ~]$ cat primary.sh
#!/bin/sh
set -e
echo 'Primary script'
trap 'echo "Got an error from the secondary script"' ERR
source secondary.sh
trap - ERR
echo 'Primary script exiting'
[galaxy => ~]$ cat secondary.sh
#!/bin/sh
echo 'Secondary script'
echo 'Secondary script generating an error'
false
echo 'Secondary script - should not be reached if sourced by primary.sh'
[galaxy => ~]$ ./primary.sh
Primary script
Secondary script
Secondary script generating an error
Got an error from the secondary script
[galaxy => ~]$
[galaxy => ~]$ cat primary.sh
#!/bin/sh
echo 'Primary script'
i=0
while [ $i = 0 ]; do
i=1
trap 'echo "Got an error from the secondary script"; break' ERR
source secondary.sh
done
trap - ERR
echo 'Primary script exiting'
[galaxy => ~]$ cat secondary.sh
#!/bin/sh
echo 'Secondary script'
echo 'Secondary script generating an error'
false
echo 'Secondary script - should not be reached if sourced by primary.sh'
[galaxy => ~]$ ./primary.sh
Primary script
Secondary script
Secondary script generating an error
Got an error from the secondary script
Primary script exiting
[galaxy => ~]$
作为奖励:截取源脚本中的错误并继续:
[galaxy => ~]$ cat primary.sh
#!/bin/sh
set -e
echo 'Primary script'
trap 'echo "Got an error from the secondary script"' ERR
source secondary.sh
trap - ERR
echo 'Primary script exiting'
[galaxy => ~]$ cat secondary.sh
#!/bin/sh
echo 'Secondary script'
set -e
echo 'Secondary script generating an error'
false
echo 'Secondary script - should not be reached'
[galaxy => ~]$ ./primary.sh
Primary script
Secondary script
Secondary script generating an error
Got an error from the secondary script
[galaxy => ~]$
[galaxy => ~]$ cat primary.sh
#!/bin/sh
set -e
echo 'Primary script'
trap 'echo "Got an error from the secondary script"' ERR
source secondary.sh
trap - ERR
echo 'Primary script exiting'
[galaxy => ~]$ cat secondary.sh
#!/bin/sh
echo 'Secondary script'
echo 'Secondary script generating an error'
false
echo 'Secondary script - should not be reached if sourced by primary.sh'
[galaxy => ~]$ ./primary.sh
Primary script
Secondary script
Secondary script generating an error
Got an error from the secondary script
[galaxy => ~]$
[galaxy => ~]$ cat primary.sh
#!/bin/sh
echo 'Primary script'
i=0
while [ $i = 0 ]; do
i=1
trap 'echo "Got an error from the secondary script"; break' ERR
source secondary.sh
done
trap - ERR
echo 'Primary script exiting'
[galaxy => ~]$ cat secondary.sh
#!/bin/sh
echo 'Secondary script'
echo 'Secondary script generating an error'
false
echo 'Secondary script - should not be reached if sourced by primary.sh'
[galaxy => ~]$ ./primary.sh
Primary script
Secondary script
Secondary script generating an error
Got an error from the secondary script
Primary script exiting
[galaxy => ~]$
设置、捕捉和取消设置对我来说相当脆弱。 因此,我更喜欢捕捉错误 这是一个我经常使用的单行程序,包括尝试一个静音的
返回
(如果源代码可用),否则退出。此外,还需要解除陷阱,否则您将无法从源代码脚本中恢复
trap'echo Error$?在线$LINENO;陷阱-错误;return 2>/dev/null | | exit'ERR
@BlueMoon OP的帖子解释了为什么这不起作用。你不能在调用环境中设置一个退出陷阱并在那里处理它吗?第二部分是误导性的-如果yourscript
设置了errexit
,包装器代码确实会在内部出现错误时中止(用bash 4.2.x测试)。与shell if-then-else的常规用法相比,这似乎有悖常理,但如果您正在寻找不可靠的代码,那么将其包装在子shell中的期望似乎一点也不不不合理。@JosipRodin我看到bash 2和3中止了整个脚本,但在4.3.30(1)-release上,它未能按描述中止。有趣的是,这种行为已经发生了很大的变化。捕捉得好。我认为当前的行为与主要建议一致——使用子shell。例如,如果您这样做:set+e;(.yourscript);如果[$?-ne 0];然后回显“初始化失败”;fi
-结果是相当合乎逻辑的。当然,寻源的重点是它不创建子shell,否则您可以正常运行它。我认为问题可能是您希望它在与父脚本相同的上下文中运行(在预处理器#include
方式中)同时在脚本中的if
中运行它。后一个动作可以修改上下文,使errexit
无效。因此,修改<代码>源代码>代码>这段过程是有标准的。我相信,只有当次要脚本没有一段时间,或者直到其中,它才起作用。是真的吗?是的,这是正确的,@kdubs。重点是要演示这个概念。没关系,我只是想确保我理解了。我认为这是个好主意,但显然子shell的stdout和stderr没有传播到外部:/1)你不应该选择一些随机整数作为退出代码-0表示成功,其他一切都不是——理想情况下,它们具有某种意义2)这不能回答问题,因为“返回0”不能帮助您捕获无法控制的脚本中的错误。