web-dev-qa-db-ja.com

bash関数での暗黙の戻り?

次のようなbash関数があるとします。

gmx(){
  echo "foo";
}

この関数は暗黙的にechoコマンドの終了値を返しますか、それともreturnが必要ですか?

gmx(){
  echo "foo";
  return $?
}

私はbashが機能する方法を想定しています。bash関数の最後のコマンドの終了ステータスは「返される」ものですが、100%確実ではありません。

11
Alexander Mills

returnは、シェル関数または「ドットスクリプト」(ソーススクリプト)からexplicitを返します。 returnが実行されない場合、Shell関数またはドットスクリプトの最後に暗黙的な戻りが行われます。

パラメータなしでreturnを実行すると、最後に実行したコマンドの終了ステータスを返すのと同じことになります。

これがreturnがすべてのPOSIXシェルで機能する方法です。

例えば、

gmx () {
  echo 'foo'
  return "$?"
}

したがって、

gmx () {
  echo 'foo'
  return
}

それは同じです

gmx () {
  echo 'foo'
}

一般に、$?を使用する必要はほとんどありません。それを将来使用するために保存する必要がある場合にのみ必要です。たとえば、その値を複数回調査する必要がある場合(その場合、その値を変数に割り当て、その変数に対して一連のテストを実行します)。

10
Kusalananda

bash(1)のmanページから:

実行すると、関数の終了ステータスは、本体で実行された最後のコマンドの終了ステータスになります。

すでに提供されている回答にいくつかの注意事項を追加します。

  • returnはシェルにとって非常に特別な意味がありますが、構文の観点から見ると、これはシェルの組み込みコマンドであり、returnステートメントは他の単純なコマンドと同様に解析されます。つまり、他のコマンドの引数と同様に、引用符で囲まれていない場合、_$?_はsplit + globの対象になります。

    したがって、それを回避するには、その_$?_を引用する必要があります。

    _return "$?"
    _
  • returnは通常、オプションを受け入れません(_ksh93_は通常の_--help_、_--man_、_--author_...を受け入れます)。期待する唯一の引数(オプション)は戻りコードです。受け入れられる戻りコードの範囲はシェルによって異なり、0..255以外の値が_$?_に正しく反映されるかどうかもシェルによって異なります。詳細は プロセス終了時のデフォルトの終了コード を参照してください。

    ほとんどのシェルは負の数を受け入れます(結局のところ、_exit()/exitgroup()システムコールに渡される引数はintであるため、値は少なくとも-2になります31 2に31-1なので、シェルがその機能に対して同じ範囲を受け入れることだけが理にかなっています)。

    ほとんどのシェルはwaitpid()およびcoを使用します。ただし、その場合、storedが_$?_にある場合、その終了ステータスを取得するためのAPIは0から255までの数値に切り捨てられます。関数の呼び出しにはプロセスの生成が含まれず、waitpid()を使用してすべてのプロセスが同じプロセスで実行されるため、終了ステータスを取得しますが、多くのシェルも関数の呼び出し時のwaitpid()の動作を模倣しています。つまり、負の値でreturnを呼び出しても、_$?_には正の数が含まれます。

    現在、returnが負の数を受け入れるシェル(ksh88、ksh93、bash、zsh、pdksh、およびmksh、yash以外の派生物)の中には、_return -- -123_それ以外の場合、_-123_は、3つの_-1_、_-2_、_-3_無効オプションとして解釈されます。

    Pdkshとその派生物(OpenBSD shまたはposhなど)は_$?_の負の数を保持するため、_return "$?"_を実行すると_$?_の場合に失敗します負の数が含まれています(最後の実行コマンドが負の数を返す関数であった場合に発生します)。

    したがって、これらのシェルでは_return -- "$?"_の方が適しています。ただし、ほとんどのシェルではサポートされていますが、その構文はPOSIXではなく、実際にはmkshおよびash派生物ではサポートされていません。

    まとめると、pdkshベースのシェルでは、関数の引数に負の数を使用できますが、そうした場合、_return "$@"_は機能しません。他のシェルでは、_return "$@"_が機能し、returnへの引数として負の数(または0..255以外の数)を使用しないでください。

  • 私が知っているすべてのシェルで、関数内で実行されているサブシェルの内側からreturnを呼び出すと、サブシェルは終了します(提供された終了ステータスがある場合は、または最後のコマンド実行の終了ステータスで)。関数からの戻り値(私には、POSIXがその保証を提供するかどうかは不明です。関数内の終了サブシェルの代わりにexitを使用する必要があると主張する人もいます)。例えば

    _f() {
      (return 3)
      echo "still inside f. Exit status: $?"
    }
    f
    echo "f exit status: $?"
    _

    出力されます:

    _still inside f. Exit status: 3
    f exit status: 0
    _
2

はい、関数の暗黙的な戻り値は、最後の実行済みコマンドの終了ステータスです。これは、シェルスクリプトのどの時点でも当てはまります。スクリプト実行シーケンスのどの時点でも、現在の終了ステータスは、最後に実行されたコマンドの終了ステータスです。変数割り当ての一部として実行されるコマンド:var=$(exit 34)。関数との違いは、関数の実行終了時に関数が終了ステータスを変更する可能性があることです。

「現在の終了ステータス」を変更する別の方法は、サブシェルを起動し、必要な終了ステータスで終了することです。

$ $(exit 34)
$ echo "$?"
34

そして、はい、終了ステータスexpansionは引用する必要があります:

$ IFS='123'
$ $(exit 34)
$ echo $?
4

(exit 34)も機能します。
より堅牢な構成は$(return 34)である必要があり、出口は実行中のスクリプトを「終了」する必要があると主張する人もいます。ただし、$(return 34)anyバージョンのbashでは機能しません。したがって、移植性はありません。

終了ステータスを設定する最も安全な方法は、関数から動作、定義、およびreturnするように設計されているので、それを使用することです。

exitstatus(){ return "${1:-"$?"}"; }

したがって、関数の最後に。何もないか、returnまたはreturn "$?"のいずれかとまったく同じです。関数の終わりは、「関数の最後のコード行」を意味する必要はありません。

#!/bin/sh
exitstatus(){ a="${1:-"$?"}"; return "$a"; }
gmx(){
    if     [ "$1" = "one" ]; then
           printf 'foo ';
           exitstatus 78
           return "$?"
    Elif   [ "$1" = "two" ]; then
           printf 'baz ';
           exitstatus 89
           return
    else
           printf 'baz ';
           exitstatus 90
    fi
}  

印刷されます:

$ ./script
foo 78
baz 89
baz 90

"$?"の唯一の実用的な用途は、その値を出力することです。echo "$?"または変数に保存します(これは一時的な値であり、コマンドを実行するたびに変更されます)。exitstatus=$?export EXITSTATUS="$?"のようなコマンドで変数を引用することを忘れないでください。

returnコマンドでは、値の有効範囲は通常0〜255ですが、126 + nの値は一部のシェルで特別な終了ステータスを通知するために使用されるため、一般的には0〜125を使用することをお勧めします。

0
Isaac