在要执行的shell脚本中,我可以使用set -e
中止错误。
但是,在源脚本中,如果稍后的命令以错误状态退出,则使用set -e
将终止原始shell。
source set_e.sh
./exit_1.sh
# shell dies
一个简单的解决方案是在脚本结尾处set +e
,但是如果使用的话,这将破坏父set -e
(如果有人将我的脚本包裹在未来)。
如何在源代码脚本中获得错误中止功能?
答案 0 :(得分:4)
这是不可能的。但是,如果您愿意,可以选择使用子shell:
(
set -e
source another.sh
)
只有调用脚本的环境永远不会被被调用的脚本改变。
注意:使用换行符分隔两个命令并不使用分号可能很重要。
答案 1 :(得分:3)
将set -e
更改为return 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
答案 2 :(得分:3)
嗯,问题不是很清楚:原始作者在拦截源脚本中的错误后想要的是什么,但是,作为解决方案的入口点,以下就足够了:
您可以在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 => ~]$
主脚本在没有“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'
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 => ~]$
答案 3 :(得分:2)
您可以检查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"
然后{b} 4.3.30中的set -e
失败会导致yourscript
失败。
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
答案 4 :(得分:1)
设置、捕捉和取消设置 set -e
对我来说相当脆弱。
因此,我更喜欢捕捉错误。
这是我经常使用的单行,包括尝试静音 return
(如果来源有效),否则 exit
。另外,取消设置陷阱,否则就会留下源脚本。
trap 'echo Error $? on line $LINENO; trap - ERR; return 2>/dev/null || exit' ERR
答案 5 :(得分:0)
您可以通过set -o
检测是否在源脚本的开头设置了errexit选项,并在源脚本的末尾恢复其原始值。