Bash関数のreturnとexitの違い


429

終了コードに関するBash関数のreturnand exitステートメントの違いは何ですか?


55
Protip:help <command>シェルを入力して、組み込みのシェルが何をするかについての情報を取得します。あなたの場合help returnhelp exit
SiegeX

回答:


318

man bashreturn [n];

関数に実行を停止させ、nで指定された値を呼び出し元に返します。nを省略すると、戻りステータスは関数本体で実行された最後のコマンドのステータスになります。

...でexit [n]

シェルをnのステータスで終了させます。nを省略すると、終了ステータスは最後に実行されたコマンドのステータスになります。EXITのトラップは、シェルが終了する前に実行されます。

編集:

質問の編集によると、終了コードに関しては、終了コードとreturnは関係ありません。終了コードは、関数ではなく、アプリケーション/スクリプトを対象としています。したがって、この点で、スクリプトの終了コードを設定する唯一のキーワード($?シェル変数を使用して呼び出し側プログラムがキャッチできるキーワード)はexitです。

編集2:

言及してexitいる私の最後の声明はいくつかのコメントを引き起こしています。これは、OP を区別returnexit、OPを理解するために作成されました。実際、プログラム/シェルスクリプトの任意の時点でexit呼び出したプロセスへの終了コードでスクリプトを終了する唯一の方法です。

シェルで実行されるすべてのコマンドは、ローカルの「終了コード」を生成します。これは、$?変数をそのコードに設定しif&&や他の演算子と共に使用して、 他のコマンドを条件付きで実行できます。

これらの終了コード(および $?変数)は、コマンドを実行するたびにリセットされます。

ちなみに、スクリプトによって実行された最後のコマンドの終了コードは、呼び出しプロセスから見たスクリプト自体の終了コードとして使用されます。

最後に、関数は、呼び出されると、終了コードに関してシェルコマンドとして機能します。(関数の)関数の終了コードは、を使用して設定しreturnます。したがって、関数return 0が実行されると、関数の実行が終了し、終了コード0が返されます。


10
ではない正確に。常に現在のシェルから値を返します。関数内にいるかどうかは関係ありません。
ディエゴセビリア

10
編集に関するコメント:戻り値と終了コードを混同しているかもしれませんがfunc(){ return 50; };func;echo $?、50をエコーし​​ます。したがって、$?シェル変数はに制限されていないようですexit
lecodesportif 2010

8
$?最後に実行されたフォアグラウンドパイプラインの終了ステータスに展開されます。」その出口は、呼び出しexit(またはスクリプトの最後を押す)の形式で、またはreturn関数内の呼び出しの形式で、シェルから出る場合があります。
SiegeX

11
@lecodesportif:$? 現在のプロセス/スクリプトのexit、このスクリプトによって実行された最後のコマンドの結果または結果に制限されます。したがって、最後のスクリプト行がその関数の呼び出しであり、その関数が50を返す場合、はい、呼び出し元のプロセスに対して$?生成するのは50です。ただし、returnこれは、現在のスクリプトに制限されています。この関数呼び出しがスクリプトの最後の文である場合にのみ返されます。exitただし、常にスクリプトを終了$? し、呼び出しプロセスに関してその値を返します
ディエゴセビリア

11
-1「行returnを終了コードとは関係ありません」と混同した場合 実験により、関数の戻りコードとスクリプトの終了コードに機能的な違いはないことがわかりました。
ジャック

296

return現在の関数がスコープ外にexitなり、スクリプトが呼び出された時点でスクリプトが終了します。これを説明するのに役立つサンプルプログラムを次に示します。

#!/bin/bash

retfunc()
{
    echo "this is retfunc()"
    return 1
}

exitfunc()
{
    echo "this is exitfunc()"
    exit 1
}

retfunc
echo "We are still here"
exitfunc
echo "We will never see this"

出力

$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()

17
いい例です。で終了値1を表示することもでき$?ます。
ディエゴセビリア

48
「retfunc」の呼び出しの前に「set -e」を追加すると、この関数は「We are still here」を出力しないことに注意してください。
Michael

4
ただし、echo fnord | while read x; do exitfunc; done; echo "still here"「まだここに」印刷されます。whileこのシナリオでは、サブシェルのみが終了しているようです。
tripleee 2013

おおよその回避策はありますdone || exit $?が、これは醜く、正確に同等ではありません。
Tripleee 2013

2
+1追加すると便利かもしれません: `` ` returnは現在の関数またはソーススクリプトをスコープ外にします ` ` 。
Isaac

56

2つがどのように使用されているかを説明していないので、質問に完全に答えた人は誰もいないと思います。OK、出口がスクリプトを強制終了することはわかっています。スクリプトが呼び出されると、出口や出口0や出口7などのステータスを割り当てることができます。これは、別のスクリプトなどから呼び出された場合にスクリプトが強制的に停止された方法を判別するために使用できます。終了時に十分です。

呼び出されたときにreturnは、関数の動作を示すために指定された値(通常は1または0)を返します。次に例を示します。

    #!/bin/bash
    isdirectory() {
      if [ -d "$1" ]
      then
        return 0
      else
        return 1
      fi
    echo "you will not see anything after the return like this text"
    }

このように確認してください:

    if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi

またはこのように:

    isdirectory || echo "not a directory"

この例では、テストを使用して、ディレクトリが見つかったかどうかを示すことができます。復帰後は関数内で実行されないことに注意してください。シェルでは0はtrueですが、falseは1であり、他のプログラム言語とは異なります。

関数の詳細:http : //www.linuxjournal.com/content/return-values-bash-functions

注:isdirectory関数は、説明のみを目的としています。これは、実際のスクリプトでこのようなオプションを実行する方法ではありません。


3
またはtest -d $1、同じ結果を得るために使用します。絶対にしないでくださいif <check> return else return<check>少なくとも、私が知っているすべての言語で同じことを行うだけです。
erikbwork

4
erikが言っていることをさらに明確にするために:ここにあるものとまったくisdirectory() { [ -d "$1" ]; }同じように動作します:シェル関数のデフォルトの戻り値は、そのコードの終わりに到達するか、return引数なしのaによるかに関わらず、最新のコマンド。
Charles Duffy

11
ここの他のコメンターは、マイクQの例のスタイルを批判していreturnます。彼の例は単純化されており、本番環境では使用されないことは事実です。しかし、それは単純なので、彼の仕事はうまくいきます。何も問題はありません。
マイクS

マイクSに感謝します。ええ、私は最も単純な例が出口と戻りを最もよく説明していることに同意します。他のコメントは確かに有効であり、より高度なbashコーダーには考慮すべきです;-)
Mike Q

1
質問に正確に関連していないと言う人もいるかもしれませんが、私がこの質問を見つけた原因となった問題に関連していて、それに答えました。:-)
Jesse Steele

33

関数はスクリプトの内部にあり、通常はreturnステートメントを使用して呼び出された場所から戻ります。外部スクリプトの呼び出しは完全に別の問題であり、スクリプトは通常、exitステートメントで終了します。

「終了コードに関するBASH関数のreturnステートメントとexitステートメントの違い」はほとんどありません。どちらもそのものではなくステータスを返します。ステータス0は成功を示し、その他のステータス(1〜255)は失敗を示します。returnステートメントは、それが呼び出された場所からスクリプトに戻りますが、exitステートメントは、スクリプト全体が出会った場所から終了します。

return 0  # returns to where the function was called.  $? contains 0 (success).

return 1  # returns to where the function was called.  $? contains 1 (failure).

exit 0  # exits the script completely.  $? contains 0 (success).

exit 1  # exits the script completely.  $? contains 1 (failure).

関数が単にreturnステートメントなしで終了する場合、最後に実行されたコマンドのステータスがステータスコードとして返されます(そして、 $?)。

戻り値と終了値は、0から255のステータスコードを返します。 $?。ステータスコードに他のものを詰め込むことはできません(たとえば、 "cat"を返す)。効果がないでしょう。ただし、スクリプトは、ステータスコードを使用して、255の失敗の理由を返すことができます。

呼び出しスクリプトに含まれる変数を設定したり、関数の結果をエコーし​​たり、呼び出しスクリプトでコマンド置換を使用したりできます。しかし、returnとexitの目的は、Cなどのプログラミング言語で期待されるような値や計算結果ではなく、ステータスコードを渡すことです。


25

場合によっては、.またはを使用してスクリプトを実行しますsource

. a.sh

あなたが含まれている場合exitではa.sh、それだけでスクリプトを終了するが、あなたのシェルセッションを終了しません。

あなたが含まれている場合returnにはa.sh、それは単にスクリプトの処理を停止します。


1
しかし、単にa.shを実行するとエラーが発生return: can only 'return' from a function or sourced scriptするため、一般的なスクリプトには適していません。
ピーター-モニカの復活2017年

スクリプトのトップレベルでは、どちらもall状況に適していません。サブシェルを生成するのではなく、現在のシェルでスクリプトを使用.またはsource実行します。スクリプトは、それがどのように使用されるかを知っている必要があります。反対のことをするユーザーにとっては悲惨です。個人的には、初めて実行する前にスクリプトを読むことをお勧めします。
ジェシーチザム2018年

3
私が遭遇した素晴らしいトリックは、 trap関数ERR EXIT最初に失敗したコマンドの終了コードを保存してからerrCode=$?、スクリプト(ソースがあるかどうかにかかわらず)を終了return $errCode || exit $errCodeする||ことです。「ソースがないために戻ることができない場合」 、代わりに終了してください。」
dragon788

6

簡単な言葉で(主にコーディングの初心者向け)、

`return` : exits the function,
`exit()` : exits the program(called as process while running)

また、観察した場合、これは非常に基本的ですが...、

`return` : is the keyword
`exit()` : is the function

1
bashスクリプトでexitは、はとほぼ同じ関数ですreturn。これらは組み込みコマンドです。予約語でさえありません。
ピーター-モニカの復活2017年

6
  • exit現在のプロセスを終了します。終了コードの有無にかかわらず、これはプログラム機能よりもシステムと見なしてください。ソーシングexitするとシェルが終了することに注意してください。ただし、実行するとexitスクリプトします。

  • return関数からは、戻りコードの有無にかかわらず、呼び出し後に命令に戻ります。returnオプションであり、関数の最後で暗黙的に行われます。return関数内でのみ使用できます。

ソースを取得している間exit、スクリプトを関数内からシェルを強制終了せずに簡単に追加することはできません。「テスト」スクリプトの例が良いと思います

#!/bin/bash
function die(){
   echo ${1:=Something terrible wrong happen}
   #... clean your trash
   exit 1
}

[ -f /whatever/ ] || die "whatever is not available"
# now we can proceed
echo "continue"

次のようにします:

user$ ./test
Whatever is not available
user$

test -および-シェルが閉じます。

user$ . ./test
Whatever is not available

のみ testが終了し、プロンプトが表示されます。

解決策は、潜在的な手順()

#!/bin/bash
function die(){
   echo $(1:=Something terrible wrong happen)
   #... clean your trash
   exit 1
}

( # added        
    [ -f /whatever/ ] || die "whatever is not available"
    # now we can proceed
    echo "continue"
) # added

現在、どちらの場合testも終了します。


を追加してそのブロック()サブシェルに配置し、サブシェルに.あるテストスクリプトを通常どおり実行した場合と同じように(ソース)コマンドを効果的に実行解除します。スクリプトのIOfが実行されない.source、2つのサブシェルが実質的に存在します。
ジェシーチザム

3

OPの質問:終了コードに関してBASH関数のreturnステートメントとexitステートメントの違いは何ですか?

最初に、いくつかの説明が必要です:

  • (return | exit)ステートメントは、(function | shell)の実行を終了する必要はありません。(関数|シェル)は、(return | exit)ステートメントがなくても、コードリストの最後に到達すると終了します。
  • (return | exit)ステートメントは、終了した(function | shell)から値を返す必要はありません。すべてのプロセスには組み込み変数$?があります。これは常に数値を持ちます。これは「?= 1」のように設定できない特別な変数ですが、特別な方法でのみ設定されます(以下の*を参照)。$の値?(呼び出された関数|サブシェル)で実行される最後のコマンドの後には、(関数の呼び出し元|親シェル)に渡される値があります。これは、最後に実行されたコマンドが( "return [n]" | "exit [n]")であるか、プレーン( "return"または呼び出された関数コードの最後のコマンドである他の何かであるかに関係なく)です。

上記の箇条書きのリストで、「(x | y)」から常に最初の項目または常に2番目の項目のいずれかを選択して、それぞれ関数とリターンまたはシェルと終了に関するステートメントを取得します。

両者が特殊変数$の一般的な使用法を共有していることは明らかですか?終了後、値を上に渡します。

*次に、その$の特別な方法については?設定できます:

  • 呼び出された関数が終了して呼び出し元に戻るとき、$?呼び出し元では、最終値$と等しくなりますか?終了した関数内。
  • 親シェルが暗黙的または明示的に単一のサブシェルで待機し、そのサブシェルの終了によって解放された場合、$?親シェルの$の最終値と等しくなりますか?終了したサブシェルで。
  • 一部の組み込み関数は$を変更できますか?結果に応じて。しかし、そうでないものもあります。
  • 組み込み関数「return」と「exit」の後に数値引数が続く場合、$?引数付きで実行を終了します。

その$に注目する価値はありますか?次のように、サブシェルでexitを呼び出すことにより、値を割り当てることができます。

# (exit 259)
# echo $?
3  

4
一部がそれを逃した場合、最終的な終了値が1バイトであるためにexit 259エコーし3ます。 259 % 256 = 3
ジェシーチザム2018年

0

まずreturn、キーワードでexit、友達が機能です。

とはいえ、ここでは最も簡単な説明を示します。

return 関数から値を返します。

exit 現在のシェルから出るか、現在のシェルを放棄します。


あんまり!あなたは論理的に間違っています。Exitはreturnキーワードですが、関数です。リターンは単なる終了コードではありません。そのため、比較は公平ではありません。
Ahmad Awais 2017年

私が主張しようとしていたことをより明確にするためにそれを編集しました。それを手伝ってくれてありがとう。
Ahmad Awais 2017年

4
exitまたreturn、「キーワード」も、bashマニュアルで「予約語」と呼ばれているものでもありません。どちらも、bash関数の意味で「関数」でもありません。どちらもbash lingoの組み込みコマンドです。(そこ呼ばれるC標準ライブラリ関数exit()、およびCプログラミング言語は、予約語を持っているreturnが、それらは、その意味が妙に似ているにもかかわらず、bashのコマンドと混同しないでください。)
ピーター-復活モニカ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.