有没有一种方法可以编写一个bash函数来中止整个执行过程,而无论其调用方式如何?


83

我在bash函数中使用“ exit 1”语句来终止整个脚本,并且运行良好:

function func()
{
   echo "Goodbye"
   exit 1
}
echo "Function call will abort"
func
echo "This will never be printed"

但是后来我意识到,当这样调用时,它不会起作用:

res=$(func)

我知道我创建了一个子shell,并且“ exit 1”中止了该子shell,而不是主要子shell...。

但是,有没有一种方法可以编写一个中止整个执行过程的函数,而无论其调用方式如何?我只需要获取实际的返回值(由函数回显)。

Answers:


90

可以做的是注册顶级外壳TERM以退出信号,然后将a发送TERM到顶级外壳:

#!/bin/bash
trap "exit 1" TERM
export TOP_PID=$$

function func()
{
   echo "Goodbye"
   kill -s TERM $TOP_PID
}

echo "Function call will abort"
echo $(func)
echo "This will never be printed"

因此,您的函数将TERM信号发送回顶层外壳,使用提供的命令(在本例中为)捕获并处理该信号"exit 1"


1
我当时在考虑Csetsid()函数,但是它的工作方式并不完全相同。已更新为不使用该setsid命令,因为它将要求我们开始一个新过程。
FatalError

3
作品。任何级别的功能嵌套,任何流程……都可以。
2012年

是否有可能使一个普通的中止()函数出这一点,使用的第一个参数的代码,例如退出abort 2会做trap "exit 2" TERM之前kill
Neil C. Obremski

@ NeilC.Obremski:好的。主要是有关如何获取值传播回顶级外壳程序的问题。可能使用类似的命令tempfile来选择将代码存储在顶部外壳中的位置,然后让要退出的外壳将代码写入该文件,然后仅读取父级的处理程序。
FatalError 2013年

2
中间有子外壳时,似乎不起作用。set -E 在此处
罗恩·伯克

42

如果命令以非零状态退出,则可以使用set -e哪个退出

set -e 
func
set +e

或获取返回值:

(func) || exit $?

3
有趣的是,我看到了一个解决方案。主脚本中的“ set -e”会导致任何返回1(或与其一起退出)的函数中止整个执行。不幸的是,“ set -e”彻底改变了所有行为,我无法使用它。
2012年

1
您应该使用(())进行数值比较。在[]内部应使用-gt,-eq等。
jordanm 2012年

16
甚至res=$(func) || exit
格伦·杰克曼

我想,@ glennjackman获取了cookie。那比我的垃圾还干净!
Brice 2012年

3
这种违背问题精神的精神。如果每个函数调用本身都需要捕获错误,那么exit 首先使用是没有意义的。该函数可以简单地返回。/但是,如果set -e是全局设置的,这样做是很有意义的
phil294

2

我想更好的是

#!/bin/bash
set -e
trap "exit 1" ERR

myfunc() {
     set -x # OPTIONAL TO SHOW ERROR
     echo "Exit with failure"
     set +x # OPTIONAL
     exit 1
}
echo "BEFORE..."
myvar="$(myfunc)"
echo "AFTER..But not shown"

1

子进程不能强制父进程隐式关闭。您需要使用某种信令机制。选项可能包括一个特殊的返回值,或者可能发送带有的信号kill,例如

function child() {
    local parent_pid="$1"
    local other="$2"
    ...
    if [[ $failed ]]; then
        kill -QUIT "$parent_pid"
    fi
}

1

但是,有没有一种方法可以编写一个中止整个执行过程的函数,而无论其调用方式如何?

没有。

我只需要获取实际的返回值(由函数回显)。

您可以

res=$(func)
echo $?
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.