exit
は、エラーが呼び出されてもスクリプトを終了しません。
Error: Could not resolve localhost
after exit
#!/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
exit
は現在のシェルプロセスを終了します¹。
$(resolve_ip)
では、resolve_ip
がサブシェルプロセスで実行されています。
できるよ:
my_ip=$(resolve_ip) || exit
master_ip=$(resolve_ip "$hostname") || exit
if [ "$my_ip" = "$master_ip" ]; ...
サブシェルがゼロ以外の終了ステータスで終了したときにメインシェルが終了する(サブシェルと同じ終了コードで)。
また、resolve_ip
はサブシェル環境で実行されるため、$ip
および$Host
変数は、そのサブシェルが戻った後は存続しません。
(...)
の(>&2 echo "Error: $1")
もサブシェルを開始することに注意してください。 stderrが壊れたパイプであり、エラーメッセージを書き込むとecho
が組み込まれているため、メインシェルプロセスにSIGPIPE配信が発生する場合を除き、ここでは実際には必要ありません。
ここでは、標準出力を介して出力を返す代わりに、ユーザーが指定した変数に保存することで出力を返すことができます。
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" ]; ...
¹厳密に言えば、サブシェル環境は子プロセスで実装する必要はなく、ksh93
などの一部のシェルは最適化としては機能しませんが、exit
はメインシェルではなくサブシェルのみを終了します。ただし、ksh93
には、サブシェル環境を含まない${ ...; }
形式またはコマンド置換があるため、exit
はメインシェルを終了します。