シェルで0はtrueですがfalseは1なのはなぜですか?


122
false; echo $?

上記は出力されます 1、これは私が知っている他のすべてのプログラミング言語と矛盾しています。

これには理由がありますか?


3
また、Unix Wayと一致しています...成功しても何も返しません。
Abdullah Jibaly 2011年

21
終了ステータスはブール値ではないためです。そのような単純な。
Jens

2
false他のプログラミング言語のように、これはブール値ではないことに注意してください。これは/bin/false/usr/bin/falseMacの)にあるプログラムで、常にエラー終了コード1を返すことを目的としていtrueます。したがって、ここにキャストするようなものはありません。終了コードがすべてです。
ミハイルヴァ

シェルは、オペレーティングシステムへの(ユーザー)インターフェイスです。Unixなどのプログラムは、回答で示された理由(複数の失敗の理由を伝える機能)のため、0をOKとして終了するという慣例に従います。シェルは単にこの規則を維持するだけなif myprog; then echo OK; fiので、構成は簡単で直感的です。そうでなければ、プログラムの成功のためにすべてのテストを逆にする必要があります!
ピーター-モニカを

回答:


93

これは慣例ですが、考えると特に便利です。一般に、プログラムが成功した場合は、それだけで十分です。ただし、失敗した場合は、失敗に関するすべての種類の情報(発生した理由、修正方法など)を知る必要がある場合があります。ゼロの「成功」の平均とゼロ以外の平均の失敗があると、成功を簡単に確認できます。必要に応じて、詳細について特定のエラーを調査します。多くのAPIとフレームワークには同様の規則があります。成功した関数は0を返し、失敗した関数は特定の失敗のケースを説明するエラーコードを返します。


6
私はこの答えを理解していますが、ブールから整数への変換が逆になる理由はまだわかりません。「ブール値を返す規則」は次のように述べていますか:trueを返す場合はエラーがないことを意味し、falseを返す場合はエラーが発生したことを意味します(より一般的な「整数=エラーコード規則」など)。
Guillaume86

1
booleanからintへの変換があると仮定すると、答えが本当に理解できなかったことを意味します。ゼロは成功を意味し、1、2、...、255はすべて、さまざまな失敗のシナリオを効果的に伝えることができるエラーコードです。特定の例では、コマンドのグループxargsどのように失敗したかを示すために、127前後の範囲のさまざまなエラーコードを使用しています。実行できる変換はintからboolへの変換で、0は成功にマップされ(true / 1として表現したいと思いますが、これは単なる別の規則であることに注意してください)、その他のすべての値は失敗します。
tripleee

79

Bashはプログラミング(スクリプト)言語ですが、シェルおよびユーザーインターフェイスでもあります。もし0エラーの、プログラムは1種類のエラーしか提示できませんでした。

ただし、Bashでは、ゼロ以外の値はすべてエラーであり、1〜255の任意の数値を使用してエラーを表すことができます。つまり、さまざまな種類のエラーが発生する可能性があります。1一般的なエラー、126ファイルを実行できない、127「コマンドが見つからない」などを意味します。ここでは、最も一般的ないくつかの終了コードを示す、特別な意味を持つBash 終了コードのリストを示します。

成功の種類も多数あります(終了ステータスはです0)。ただし、成功すると次のステップに進むことができます。結果を画面に出力したり、コマンドを実行したりできます。


8
さまざまな戻りコードの有用性を示すこの実用的な答えは、他のいくつかの答えの説得力よりも好ましいです。
javadba

1
そして、楽しさのために、/usr/include/sysexits.hノートが1980年代にさかのぼる慣例であるとしても、ノートはおそらくより野心的な出口値を指摘します。この規則はbashの範囲外にあります。
ghoti 2018

2
素晴らしく、シンプルで実用的な説明。これは一番上にある必要があります。
レイレナードアモラト

3
0エラーの場合、プログラムは1種類のエラーしか提示できませんでした」。このステートメントが鍵であり、この答えがトップにあるべき理由です。
rayryeng

1
@LuisLavaireそれは未定義の動作です。実際には、数値は切り捨てられる傾向があります。しかし、ランタイムが警告を生成したり、単にクラッシュしたりする場合は、「もっと間違っている」ことは間違いありません。OSはこの情報用に1バイトを予約しており、そこに複数のバイトを配置しようとすると、間違いなくエラーが発生します。しかし、OS設計者はおそらく初日にクラッシュし、肩をすくめて、できる限りのことは値を切り捨てて先に進むことだと判断しました。
tripleee

30

ここには2つの関連する問題があります。

最初に、OPの質問、なぜシェルでは0はtrueですがfalseは1ですか?2番目に、なぜアプリケーションは成功した場合に0を返し、失敗した場合にゼロ以外を返すのですか?

OPの質問に答えるには、2番目の質問を理解する必要があります。この投稿に対する多数の回答は、これが慣習であることを説明しており、この慣習が提供する優れた点のいくつかをリストしています。これらの機能のいくつかを以下にまとめます。

アプリケーションが成功すると0を返し、失敗するとゼロ以外を返すのはなぜですか?

操作を呼び出すコードは、操作の終了ステータスについて2つのことを知る必要があります。操作は正常に終了しましたか?[* 1]そして、操作が正常に終了しない場合、なぜ操作が正常に終了しなかったのですか?任意の値を使用して成功を表すことができます。ただし、0はプラットフォーム間で移植可能であるため、他のどの数値よりも便利です。2011年8月16日のこの質問に対するxiboの回答の要約:

ゼロはエンコーディングに依存しません。

one(1)を32ビット整数ワードに格納する場合、最初の質問は「ビッグエンディアンワードかリトルエンディアンワードか?」で、「リトルエンディアンワードを構成するバイトの長さはどのくらいですか?」 "、ゼロは常に同じに見えますが。

また、一部の人々はerrnoをある時点でcharまたはshortにキャストしたり、浮動にしたりすることも予想されます。(int)((char)ENOLCK)は、charが少なくとも8ビット長でない場合(7ビットASCII charマシンはUNIXでサポートされています)、ENOLCKではありませんが、(int)((char)0)は、イワナの建築の細部。

0が成功の戻り値であると判断されたら、失敗にはゼロ以外の値を使用するのが理にかなっています。これにより、多くの終了コードが、操作が失敗した理由の質問に答えることができます。

シェルで0はtrueですがfalseは1なのはなぜですか?

シェルの基本的な使用法の1つは、スクリプトを作成してプロセスを自動化することです。通常、これは操作を呼び出し、操作の終了ステータスに基づいて条件付きで何か他のことを行うことを意味します。フィリップA.はこの投稿に対する彼の回答でうまく説明しました

一般的にbashおよびUNIXシェルでは、戻り値はブール値ではありません。これらは整数の終了コードです。

次に、これらの操作の終了ステータスをブール値として解釈する必要があります。成功(0)終了ステータスをtrueに、ゼロ以外/失敗の終了ステータスをfalse にマップすることは理にかなっています。これを行うと、チェーンシェルコマンドを条件付きで実行できます。

以下に例を示しmkdir deleteme && cd $_ && pwdます。シェルは0をtrueと解釈するため、このコマンドは期待どおりに機能します。シェルが0をfalseと解釈する場合は、各操作で解釈された終了ステータスを反転する必要があります。

要するに、アプリケーションが正常終了ステータスに対して0を返すという慣例を考えると、シェルが0をfalseとして解釈するのは無意味です。


[* 1]:はい、多くの場合、オペレーションは単なる成功メッセージ以上のものを返す必要がありますが、それはこのスレッドの範囲を超えています。

Advanced Bash-Scripting GuideのAppendix Eも参照してください


2
こんにちは、強調しておきますが、シェルが0をfalseとして解釈し、0以外をtrueとして解釈する場合、そのトリックはmkdir deleteme && cd _$ && pwd実際には失敗しません。しかし、それをに置き換える必要がmkdir deleteme || cd _$ || pwdあります。私の意見では、私たちが実際に実行したいのはmkdir deletemeandcd _$and」なのでpwd ...(ここで「and」は通常の言語からの意味を持っているため)であるためです。
レミPeyre

1
私はそれを私の答えでカバーしたと思います。ただし、明確にするために、ロジックを反転する場合、&&演算子を||演算子に置き換えるだけでは不十分です。De Morganの法則を完全に適用する必要があります。参照:en.wikipedia.org/wiki/De_Morgan%27s_laws
axiopisty

1
別の考慮事項:一般的に、trueゼロにfalse対応し、非ゼロに対応することを述べるのが自然である理由として、少なくとも3つの理由が考えられます。まず、私があなたに何かを言うと、「あなたに真実を言ったか」は私が言った嘘の数に依存します:それがゼロであり、私が(全体的に)真実を言ったか、またはそれが非ゼロで私が嘘をついたかです。これは、論理andを加算の一般的な「and」に対応させることと本質的に同じです(当然、自然数に制限する場合)。
レミPeyre

1
(前のコメントからの続き)。2つ目の理由は、真実は1つですが、非真理は多数あるためです。したがって、の唯一の値trueとの他のすべての値を関連付ける方が便利ですfalse。(これは基本的にプログラムの戻り値に関する考慮事項と同じです)。
レミPeyre

(前のコメントからの続き)。3番目の理由は、「Aの真の真」は「Aの真」と同じ、「Aの偽」は「Aの偽」と同じである、などです。したがってtrue、乗法1およびfalse乗法-1として動作します。これは、-1の累乗trueとして、「偶数」およびfalse「奇数」として追加的に動作することを意味します。繰り返しになりますが、これはtrueゼロに値するものです...
レミペイヤー

17

私が理解しておくべき重要だと思う基本的な点はこれです。一般的にbashおよびUNIXシェルでは、戻り値はブール値ではありません。これらは整数の終了コードです。したがって、0は成功を意味し、他の値はエラーを意味するという慣例に従ってそれらを評価する必要があります。

test[ ]または[[ ]]オペレータ、bashの条件は、0の終了コード(の/ binに/真の結果)の場合に真と評価します。それ以外の場合は、falseと評価されます。

文字列は、終了コードとは異なる方法で評価されます。

if [ 0 ] ; then echo not null ; fi
if [ $(echo 0) ] ; then echo not null ; fi

if [ -z "" ] ; then echo null ; fi

(( ))算術演算子は、真と偽のように1と0を解釈します。ただし、その演算子はtest[ ]またはの完全な代替として使用できません[[ ]]。次に、算術演算子が役立つ場合の例を示します。

for (( counter = 0 ; counter < 10 ; counter ++ )) ; do
  if (( counter % 2 )) ; then echo "odd number $counter" ; fi
done

true / falseの括弧対括弧の説明をありがとう
javadba

15

0の終了コードが成功を意味するのは単なる慣例です。 EXIT_SUCCESSほとんどすべての最新システムでは0になります。

編集:

「なぜテスト0とテスト1の両方が0(成功)を返すのですか?」

それはまったく別の質問です。答えは、単一の引数をテストに渡すと、その引数がnull文字列( "")でない限り、常に成功するということです。Open Groupのドキュメントを参照してください。


それでは、なぜ両方とも0(成功)test 0test 1返すのですか?
httpinterpret 2010年

5
@httpinterpret、test数値をテストしません。その文字列がnull文字列かどうかをテストします。 man test詳細については。
カールノルム

12

通常、プログラムは成功するとゼロを返し、失敗するとゼロ以外を返します。false0は便利なゼロ以外の値であるため1を返しますが、一般的にゼロ以外の値は何らかの失敗を意味し、多くのプログラムは異なる失敗モードを示すために異なるゼロ以外の値を返します


2
説明のない(または明らかな理由のない)反対投票は、コミュニティをまったく支援していないため、何もしなくても、それを行う人々は不十分です。
Abdullah Jibaly 2011年

1
それを容認しないでください…しかし、それ彼らの2点です...そして@MichaelMrozek .. 19.6kで、それは悪くないでしょう、笑。
Alex Grey

1
@alexgrayこれは2年前のことです。当時私は約5kを持っていました。そして、私は担当者についてよりも答えのどこが間違っているのかを知りたいと思っていました
Michael Mrozek


4

これはUnixの初期にさかのぼる慣習です。

慣例により、すべてのシステムコールは、成功した場合は0を返し、それ以外の場合はゼロ以外を返します。これは、異なる番号を使用して異なる失敗の理由を示すことができるためです。

シェルはこの規則に従います。0は最後のコマンドが成功したことを意味し、それ以外の場合はゼロ以外を意味します。同様に、ゼロ以外の戻り値は、出力エラーメッセージに便利です。たとえば、1:「脳死」、2:「無情」などです。


これが答えです。
ピーター-モニカを

3

真/偽を成功/失敗と同等にしようとするあなたの試み。

最初は微妙に異なりますが、完全に2つです!

シェルスクリプトでは、true / falseのようなものはありません。シェルの「式」は、true / falseとして解釈されません。むしろ、シェルの「式」は成功または失敗するプロセスです。

明らかに、プロセスは多くの理由で失敗する可能性があります。したがって、起こりうる障害をマッピングするには、より大きなセットコードが必要です。正の整数でうまくいきます。一方、プロセスが成功した場合は、プロセスが実行するはずだったとおりに実行されたことを意味します。これを行う方法は1つだけなので、必要なコードは1つだけです。0がトリックです。

Cでは、プログラムを作成しています。シェルスクリプトでは、何かを実行するために一連のプログラムを実行しています。

差!


ややこしい。「man [」と入力します。テストユーティリティが式を評価し、trueと評価された場合は、ゼロ(true)の終了ステータスを返します。それ以外の場合は1(false)を返します。式がない場合、testは1(false)も返します。
カバルケード2016年

1

多分それを覚える良い方法は:

  • 戻りコードは「答えは何ですか?」と答えます。true(または他の結果)またはfalse
  • 終了コードは「問題は何ですか?」と答えます。終了コードまたは問題なし(0)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.