bash从函数内部退出脚本

时间:2016-09-08 20:15:15

标签: linux bash

在某些情况下,您希望从函数内部终止脚本:

function die_if_fatal(){
    ....
    [ fatal ] && <termination statement>
}

如果脚本来源$ . script,则终止语句为:

    正如预期的那样,
  • return将从 die 返回,但不会完成脚本
  • exit终止会话(不返回脚本)。

现在,如果脚本已执行:chmod +x script; ./script

    正如预期的那样,
  • return将从 die 返回,但不会完成脚本
  • exit不会返回die并终止脚本。

简单的方法是使用返回代码并在返回时检查它们,但是,我需要停止父代,而不修改调用者脚本。

有一些替代方法可以解决这个问题,但是,想象一下你在复杂的脚本中是5级,你会发现脚本必须结束;也许是一个“魔术”退出代码?我只想要源代码上的执行行为。

我正在寻找一个简单的声明来结束正在运行的源脚本。

在采购时,从函数内部完成脚本的正确方法是什么?

2 个答案:

答案 0 :(得分:0)

假设您的脚本不会从循环内部获取,您可以将脚本的主体封装到一个人为的一次性循环中,并使用break命令打破脚本。

将这个想法正式化并提供一些支持实用程序,您的脚本必须具有以下结构:

#!/bin/bash

my_exit_code=''
bailout() {
    my_exit_code=${1:-0}

    # hopefully there will be less than 10000 enclosing loops
    break 10000
}

set_exit_code() {
    local s=$?
    if [[ -z $my_exit_code ]]
    then
        return $s
    fi
    return $my_exit_code
}

###### functions #######

# Define your functions here.
#
# Finish the script from inside a function by calling 'bailout [exit_code]'

#### end functions #####

for dummy in once;
do

    # main body of the script
    # 
    # finish the script by calling 'bailout [exit_code]'

done
set_exit_code

答案 1 :(得分:0)

我的想法是基于 PGID (流程组标识符)和 SID (会话标识符)。除非您直接从会话负责人处获取脚本,否则以下解决方案仍然有效。另一方面,会话领导者主​​要是守护进程和交互式shell。您可以ps aux | awk '$8 ~ /s/ { print }'验证哪些进程作为会话负责人运行。

来源

/tmp/my_quit.sh

get_pid()
{
    pgid=$( ps -q $$ -o pgid= )
    sid=$( ps -q $$ -o sid= )
    if [[ $pgid == $sid ]]; then
        echo 0
    else
        echo $pgid
    fi
}

fatal()
{
    echo "1"
}

die_if_fatal()
{
    if [ $(fatal) -ne 0 ]; then
        pid=$( get_pid )
        if [ $pid -ne 0 ]; then
            echo "      >> Kill $pid"
            kill $pid
        else
            return
        fi
    fi
    echo "Rest of die_if_fatal's logic"
}

die_if_fatal
echo "      >> Sourced from a session leader. Will not end the process."

/tmp/pack1.sh

echo "$0: PID: $$ PGID: $( ps -q $$ -o pgid= ) SID=$( ps -q $$ -o sid= )"
echo "  >> Sourcing my_quit..."
. /tmp/my_quit.sh
echo "  >> Executing my_quit..."
/tmp/my_quit.sh

/tmp/pack2.sh

echo "$0: PID: $$ PGID: $( ps -q $$ -o pgid= ) SID=$( ps -q $$ -o sid= )"
echo "Sourcing pack1..."
. /tmp/pack1.sh
echo "Executing pack1"
/tmp/pack1.sh

用例

直接从shell执行die_if_fatal(my_quit.sh) - 上面没有脚本

执行脚本:

[kan@pckan ~]$ /tmp/my_quit.sh 
      >> Kill 11360
Finished
[kan@pckan ~]$

来源剧本:

[kan@pckan ~]$ . /tmp/my_quit.sh 
      >> Sourced from a session leader. Will not end the process.
[kan@pckan ~]$ 

pack1.sh 执行 - 1级嵌套

从shell执行 pack1.sh

[kan@pckan ~]$ /tmp/pack1.sh 
/tmp/pack1.sh: PID: 11260 PGID: 11260 SID= 1630
  >> Sourcing my_quit...
      >> Kill 11260
Finished
[kan@pckan ~]$

从shell中获取 pack1.sh

[kan@pckan ~]$ . /tmp/pack1.sh 
/bin/bash: PID: 1630 PGID:  1630 SID= 1630
  >> Sourcing my_quit...
      >> Sourced from a session leader. Will not end the process.
  >> Executing my_quit...
      >> Kill 11316
Finished
[kan@pckan ~]$

pack2.sh 执行 - 2个(可能更多)嵌套级别

从shell执行pack2.sh:

[kan@pckan ~]$ /tmp/pack2.sh
/tmp/pack2.sh: PID: 11535 PGID: 11535 SID= 1630
Sourcing pack1...
/tmp/pack2.sh: PID: 11535 PGID: 11535 SID= 1630
  >> Sourcing my_quit...
      >> Kill 11535
Finished
[kan@pckan ~]$ 

从shell采购pack2.sh:

[kan@pckan ~]$ . /tmp/pack2.sh
/bin/bash: PID: 1630 PGID:  1630 SID= 1630
Sourcing pack1...
/bin/bash: PID: 1630 PGID:  1630 SID= 1630
  >> Sourcing my_quit...
      >> Sourced from a session leader. Will not end the process.
  >> Executing my_quit...
      >> Kill 11618
Finished
Executing pack1
/tmp/pack1.sh: PID: 11627 PGID: 11627 SID= 1630
  >> Sourcing my_quit...
      >> Kill 11627
Finished
[kan@pckan ~]$