退出不终止脚本

cla*_*rkk 8 shell exit command-substitution subshell

exit 调用错误时不会终止脚本..

输出

Error: Could not resolve localhost
after exit
Run Code Online (Sandbox Code Playgroud)

脚本

#!/bin/sh

resolve_ip (){
    if [ -z "$1" ]; then
        host="localhost"
        ip=$(dig +short myip.opendns.com @resolver1.opendns.com)
    else
        host="$1"
        ip=$(dig +short $1)
    fi

    if [ -z "$ip" ]; then
        error "Could not resolve $host"
    fi

    echo "$ip"
}

error (){
    (>&2 echo "Error: $1")
    exit 1
}

master_host='google.com'

if [ "$(resolve_ip)" = "$(resolve_ip $master_host)" ]; then
    error "some error"
fi

echo "after exit"
exit
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 19

exit 退出当前的 shell 进程¹。

$(resolve_ip),resolve_ip正在子shell进程中运行。

你可以做:

my_ip=$(resolve_ip) || exit
master_ip=$(resolve_ip "$hostname") || exit
if [ "$my_ip" = "$master_ip" ]; ...
Run Code Online (Sandbox Code Playgroud)

当子shell以非零退出状态退出时,主shell退出(与子shell具有相同的退出代码)。

此外,由于resolve_ip在子 shell 环境中运行,在该子shell 返回后$ip$host变量将不再存在。

另请注意,(...)in(>&2 echo "Error: $1")还启动了一个子shell。除非您想涵盖 stderr 是一个损坏的管道并且写入错误消息会导致 SIGPIPE 传递到echo内置的主 shell 进程的情况,否则这里并不是真正必要的。

在这里,您可以通过将其存储在用户提供的变量中来返回它,而不是通过 stdout 返回输出:

resolve_ip (){ # args: ip_var [host]
    if [ "$#" -eq 1 ]; then
        host=localhost
        eval "$1="'$(dig +short myip.opendns.com @resolver1.opendns.com)'
    else
        host=$2
        eval "$1="'$(dig +short "$2")'
    fi

    if eval '[ -z "${'"$1"'}" ]'; then
        error "Could not resolve $host"
    fi
}

# ...

resolve_ip my_ip
resolve_ip master_ip "$hostname"

if [ "$my_ip" = "$master_ip" ]; ...
Run Code Online (Sandbox Code Playgroud)

¹ 严格来说,子shell 环境不必用子进程来实现,一些shellksh93也不是作为优化,但仍然exit只退出子shell,而不是主shell。ksh93但是有一个${ ...; }不涉及子shell环境的形式或命令替换,因此exit会退出主shell。