関数出力が変数に割り当てられると、スクリプトは終了しません。

関数出力が変数に割り当てられると、スクリプトは終了しません。

以下のサンプルスクリプトに関するいくつかの質問があります。

関数を呼び出し_fooてその出力を変数としてキャプチャしたいのですが、戻り状態(ORではない可能性があります$bar)を使用するか、失敗した場合(0以外の場合)スクリプトを停止しようとしています。01exit

  • このように呼び出すとin関数が機能しないのはなぜですかexit_fooif ! bar="$(_foo)")。 「normal」が呼び出されると動作します。
    • exitifステートメントを次のように変更すると(ただし出力が失われる)、スクリプトは停止します。if ! _foo ; then
    • これはスクリプトexitのように動作し、停止しません。returnif ! bar="$(_foo)" ; then
    • 割り当てと終了なしで関数を呼び出すだけで問題ありませんが、これを呼び出すわけではvar="$(func)"ありません。
  • _foo関数でintoの出力をキャプチャし$barて戻り状態を使用するより良い方法はありますか(またはステートメント0以外の場合は?)1case

どういうわけか使用しなければならないような感じがしますtrap


簡単な例は次のとおりです。

#!/usr/bin/env bash

set -e
set -u
set -o pipefail

_foo() {
    local _retval
    echo "baz" && false
    _retval=$?
    exit ${_retval}
}

echo "start"

if ! bar="$(_foo)" ; then
    echo "foo failed"
else
    echo "foo passed"
fi

echo "${bar}"
echo "end"

出力は次のとおりです。

$ ./foo.sh 
start
foo failed
baz
end

以下はいくつかの追加例です。

これで終了します。

#!/usr/bin/env bash

set -e
set -u
set -o pipefail

func() {
    echo "func"
    exit
}

var=''
func
echo "var is ${var}"
echo "did not exit"

終了しません。

#!/usr/bin/env bash

set -e
set -u
set -o pipefail

func() {
    echo "func"
    exit
}

var=''
var="$(func)"
echo "var is ${var}"
echo "did not exit"

答え1

exit関数だけでなく、関数内でスクリプト全体を終了します(サブシェルにもかかわらず)。おとぎ話:

#!/bin/bash
f() {
   exit 3
}
f
exit 0

上記のスクリプトは終了コード3で終了します。

#!/bin/bash
f() {
   exit 3
}
(f)
exit 0

終了コード 0 で終了します。

$(command)使用中の構文はサブシェル内で実行され、サブシェルがcommand実行exitされているレベルからのみ外れることがあります。以内に

サブシェルで実行されている項目の終了コードと出力をキャプチャしたい場合は、サブシェルが開始された環境で引き続き使用できます。

#!/bin/bash
subshelloutput="$( echo "output"; exit 3 )"
returnval=$?  # captures subshell's exit code
: more stuff follows

答え2

他の方法でも行うことができます。

_foo () 
{ 
    local _retval
    declare -n output="$1"     # $output is local (by default with declare in a func.)
                               ## and points to $1
    output="baz" && false
    _retval=$?
    echo ${_retval}            # change echo to exit
}

それでは_foo、次のように呼び出します。

$ _foo bar
1
$ echo "$bar"
baz

関数定義からに変更すると、echoスクリプトは終了します。exitexit

関連情報