Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash:源代码脚本中出现错误时停止_Bash_Shell - Fatal编程技术网

Bash:源代码脚本中出现错误时停止

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选项,并在源代码脚本的结尾恢复其原始值。您可

在要执行的shell脚本中,我可以使用
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”不能帮助您捕获无法控制的脚本中的错误。