bash関数での暗黙の戻り?


11

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

gmx(){
  echo "foo";
}

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

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

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

回答:


10

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

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

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

例えば、

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

したがって、

gmx () {
  echo 'foo'
  return
}

それは同じです

gmx () {
  echo 'foo'
}

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


2
を使用するreturnことの欠点の1つは、のようf() (...; cmd; return)に定義された関数の場合cmd、サブシェルと同じプロセスでいくつかのシェルがを実行することによる最適化が妨げられることです。多くのシェルでは、それはまた、関数の終了ステータスが、cmd持っているときにkillされた情報を運ばないことを意味します(ほとんどのシェルは、とにかくその情報を取得できません)。
ステファンChazelas

1
pdkshとその派生物(OpenBSD shやなどposh)のいくつかではreturn -- "$?"、最後のコマンドが負の数を返す関数である可能性がある場合に必要になることに注意してください。mksh(これもpdkshに基づく)関数が負の値を返すことを禁止します。
ステファンChazelas

このおかげで、私はどのようにreturn x機能が異なるのか理解できませんexit x...私が知っている唯一のことはreturn x、現在のプロセスを終了しないことです。
Alexander Mills、

@AlexanderMillsええと、それreturnは私が言ったことです:関数またはドットスクリプトから戻るために使用されます。exitまったく異なる処理を実行します(プロセスを終了します)。
クサラナンダ

ええ、それは理にかなっていると思います。これについては、より適切に対処し始めていると思います
Alexander Mills

7

bash(1)manページから:

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


右、そして帰結はreturnステートメントが終了ステータスにすぎないということかもしれませんか?
Alexander Mills、

return組み込みコマンドだと思います- などreturn 1とは異なりますがexit 1
Alexander Mills

1
「return [n]:関数の実行を停止し、nで指定された値を呼び出し元に返します。nを省略した場合、戻りステータスは、関数本体で実行された最後のコマンドのステータスです。」(同上)したがって、return指定されている場合、関数の終了ステータスを特定の値に強制します。
イグナシオバスケスエイブラムス

1
@AlexandwrMillsはい、returnexitを除いて、両方のビルトインされているreturn関数内でのみ使用することができます。でスクリプトを終了することはできませんreturn。終了ステータスは、コマンドが返す値です。returnその値を返すコマンドです。したがって、「returnステートメントは単に終了ステータスにすぎない」というのは、まったく正確ではありません。1つは値で、もう1つはコマンドと値です。
Sergiy Kolodyazhnyy

1
@AlexanderMills returnは関数から戻り、exitシェル全体を終了します。これは、Cとreturnvs. exit(n)、またはreturnvs. sys.exit()Python とまったく同じです。
ilkkachu

2

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

  • たとえreturnシェルに非常に特別な意味は、ビューの構文の観点から、それはシェルの組み込みコマンドですし、return文は、他の単純なコマンドのように解析されます。つまり、他のコマンドの引数と同様に、$?引用符で囲まれていない場合は、split + globの対象になります。

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

    return "$?"
  • return通常、任意のオプションを(受け入れないksh93のはいつものを受け入れ--help--man--author...が)。期待する唯一の引数(オプション)は戻りコードです。受け入れられる戻りコードの範囲はシェルごとに異なり、0..255以外の値が適切に反映されるかどうかも$?シェルごとに異なります。プロセス終了時のデフォルトの終了コードを参照してください詳細については。

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

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

    今、これらのシェルのうち、そのがreturn、それはのように書く必要があるいくつかの(pdkshのとヤシュ)があり、負数(ksh88では、は、ksh93は、bash、zshの、pdkshのとmksh以外誘導体、ヤシュ)を受け入れ、return -- -123そうでない場合として-1233としたが-1-2-3無効なオプション。

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

    だからreturn -- "$?"、それらのシェルでより良いでしょう。ただし、ほとんどのシェルではサポートされていますが、その構文はPOSIXではなく、実際にはサポートされていません。mksh ash派生物で。

    つまり、まとめると、pdkshベースのシェルでは、関数の引数に負の数を使用できますが、使用すると機能しreturn "$@"ません。他のシェルでreturn "$@"は機能します。負の数(または0..255以外の数)をの引数として使用することは避けてくださいreturn

  • 私が知っているすべてのシェルで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

0

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

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

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

そして、はい、終了ステータスの展開を引用する必要があります。

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

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

終了ステータスを設定する最も安全な方法は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までを使用することです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.