シェルスクリプトでブール変数を宣言して使用するにはどうすればよいですか?


980

次の構文を使用して、シェルスクリプトでブール変数を宣言しようとしました。

variable=$false

variable=$true

これは正しいです?また、その変数を更新したい場合、同じ構文を使用しますか?最後に、ブール変数を式として使用するための次の構文は正しいですか?

if [ $variable ]

if [ !$variable ]

73
注意してください! trueそしてfalse最もスニペットの文脈の中で、以下の単なる文字列、ありませんbash built-ins!以下のMike Holtの回答を読んでください。(これは、投票数が多く受け入れられた回答がIMHOの混乱を招き、投票数の少ない回答に洞察に満ちたコンテンツを
隠す

7
@mjvこの質問(およびMikuの回答)に関する混乱のほとんどは、Mikuの回答がbashビルトインの呼び出しにどのように関与したかを説明するいくつかのコメントが投稿された、Mikuがある時点で彼の回答を修正したためtrueです。ミクの元の答えはtrue組み込みを実際に呼び出しましたが、改訂された答えはそうではありませんでした。これにより、Mikuのコードがどのように機能するかについて、コメントが間違っているように見えました。ミクの回答は、元のコードと改訂されたコードの両方を明示的に示すように編集されています。うまくいけば、これは混乱を一瞬休ませるでしょう。
マイク・ホルト

2
[ true ] && echo yes, true is trueand(upppsss)[ false ] && echo yes, false is also true。/ bin / trueおよび/ bin / falseは戻りコード$?を返します。比較用ではない関数用。
fcm 2018

varがvariable=somethingtrueよりも設定されている場合、設定されvariable=ていない場合はfalseに[[ $variable ]] && echo true || echo falseなり、逆になります[[ ! $variable ]] && echo false || echo true
Ivan

回答:


1202

改訂された回答(2014年2月12日)

the_world_is_flat=true
# ...do something interesting...
if [ "$the_world_is_flat" = true ] ; then
    echo 'Be careful not to fall off!'
fi

元の回答

警告:https ://stackoverflow.com/a/21210966/89391

the_world_is_flat=true
# ...do something interesting...
if $the_world_is_flat ; then
    echo 'Be careful not to fall off!'
fi

From:Bashでブール変数を使用する

元の回答がここに含まれているのは、2014年2月12日の改訂前のコメントは元の回答のみに関するものであり、改訂された回答に関連付けられているコメントの多くは間違っているためです。たとえばtrue、2010年6月2日のbashビルトインに関するデニスウィリアムソンのコメントは、元の回答にのみ適用され、改訂版には適用されません。


37
何が起こっているのかを説明するために、ifステートメントはBashビルトインである変数の内容を実行していますtrue。変数の値として任意のコマンドを設定でき、その終了値が評価されます。
追って通知があるまで一時停止。

7
@pms演算子 "-o"および "-a"は、 "test"コマンド(別名 "[]")専用です。代わりに、これは「テスト」なしの「if +コマンド」です。(「if grep foo file; then ...」のように。)したがって、通常の演算子&&||演算子を使用します# t1=true; t2=true; f1=false;if $t1 || $f1; then echo is_true ; else echo is_false; fi; (t1 = trueからif $t1 && $f1 || $t2; then echo is_true ; else echo is_false; fi 「true」を返します(t2 = trueから「true」を返します)。繰り返しますが、「true」/「false」はbash-builtins(true / falseを返す)であるため、これだけが機能します。varがcmd(つまり、trueまたはfalse)でない限り、「if $ var ...」は使用できません
マイケル

14
-1、説明については私の回答参照してください
デニス

3
ここには多くの誤った情報があります。/ bin / trueが効果的に使用されていません。デニスの答えを見てください。
ajk 2014

1
このコードは同じではなく、リンクされた記事と同じようには機能しません。リンクされたコードは、変数に格納された名前でプログラムを呼び出しますが、この回答のコードは単なる文字列比較です。
Quolonelの質問2015

794

TL; DR

bool=true

if [ "$bool" = true ]

ミクの(元の)答えの問題

承認された回答お勧めしませ1。構文はきれいですが、いくつか欠点があります。

次の条件があるとします。

if $var; then
  echo 'Muahahaha!'
fi

次のケース2では、この条件はtrueと評価され、ネストされたコマンドを実行します

# Variable var not defined beforehand. Case 1
var=''  # Equivalent to var="".        Case 2
var=    #                              Case 3
unset var  #                           Case 4
var='<some valid command>'  #          Case 5

通常var、この例では「ブール」変数が明示的にtrueに設定されている場合にのみ、条件をtrueに評価します。他のすべてのケースは危険なほど誤解を招くものです!

最後のケース(#5)は、変数に含まれているコマンドを実行するため、特にいたずらです(有効なコマンドに対して条件がtrueと評価されるのはこのためです3、4)。

以下は無害な例です。

var='echo this text will be displayed when the condition is evaluated'
if $var; then
  echo 'Muahahaha!'
fi

# Outputs:
# this text will be displayed when the condition is evaluated
# Muahahaha!

変数の引用はより安全if "$var"; thenです。上記の場合、コマンドが見つからないという警告が表示されます。しかし、私たちはまだもっと上手くいくことができます(下部にある私の推奨事項を参照してください)。

Miku HoltによるMikuの元の回答の説明も参照してください。

Hbarの回答に関する問題

このアプローチには、予期しない動作もあります。

var=false
if [ $var ]; then
  echo "This won't print, var is false!"
fi

# Outputs:
# This won't print, var is false!

上記の条件はfalseと評価されるため、ネストされたステートメントは実行されません。驚き!

値を引用する("false")、変数を引用する("$var")、testまたはの[[代わりにまたはを使用[しても、違いはありません。

お勧めすること:

ここでは、「ブール値」を確認する方法を紹介します。彼らは期待どおりに動作します。

bool=true

if [ "$bool" = true ]; then
if [ "$bool" = "true" ]; then

if [[ "$bool" = true ]]; then
if [[ "$bool" = "true" ]]; then
if [[ "$bool" == true ]]; then
if [[ "$bool" == "true" ]]; then

if test "$bool" = true; then
if test "$bool" = "true"; then

それらはすべてほぼ同等です。他の回答5のアプローチよりもいくつかのキーストロークを入力する必要がありますが、コードはより防御的になります。


脚注

  1. ミクの回答は編集され、(既知の)欠陥はなくなりました。
  2. 完全なリストではありません。
  3. このコンテキストで有効なコマンドは、存在するコマンドを意味します。コマンドが正しく使用されているか、誤って使用されているかは関係ありません。たとえばman woman、そのようなmanページが存在しない場合でも、有効なコマンドと見なされます。
  4. 無効な(存在しない)コマンドの場合、Bashはコマンドが見つからなかったと単に警告します。
  5. 長さを気にする場合は、最初の推奨が最短です。

8
使用==して[か、test移植性がありません。可搬性を考慮することが唯一の利点である[/それtest以上である[[、と固執する=
chepner 2014

2
@Scott私はを私の主要なシェルとして使用しています。私の意見では、bashに比べて健全なスクリプト言語があります。
Dennis、

1
ええ、私はコメントでこの隠されたジョークに対する感謝を見つけることができなかったので、それを指摘しなければなりませんでした=)
Kranach

5
私にとっては、概念的にはbool = "true"を使用する方が理解しやすいです。次に、それが単なる文字列であり、特別な値や組み込みではないことは明らかです。
wisbucky 2015年

1
@dolmen絶対に、入力を制御するときに入力を評価することはそれほど危険ではありませんが、簡単に回避できる場合は回避すべき悪い習慣だと私はまだ考えています。前者のスタイルを見ただけで使用したことがある人は、予期しない動作を引き起こす可能性があるその欠陥については知らないかもしれません。
Dennis

175

Bashビルトインについて、trueより具体的には、Bashが括弧内の式を展開して解釈する方法について、いくつかの誤解があるようです。

mikuの回答のコードは、Bashビルトインtrue/bin/true、その他のtrueコマンドの種類とはまったく関係ありません。この場合、trueは単なる文字列にすぎずtrue、変数の割り当てや条件式の評価によっても、コマンド/ビルドへの呼び出しは行われません。

次のコードは、機能的にはミクの答えのコードと同じです。

the_world_is_flat=yeah
if [ "$the_world_is_flat" = yeah ]; then
    echo 'Be careful not to fall off!'
fi

ここでの唯一の違いは、比較される4つの文字が、「t」、「r」、「u」、および「e」ではなく、「y」、「e」、「a」、および「h」であることです。それでおしまい。namedや組み込みコマンドを呼び出そうとする試みはなくyeah、(mikuの例では)Bashがトークンを解析するときに行われる特別な処理もありませんtrue。それは単なる文字列であり、完全に任意のものです。

更新(2014-02-19): mikuの回答のリンクをたどると、混乱の原因がどこにあるのかがわかります。ミクの答えは単一の角かっこを使用していますが、彼がリンクするコードスニペットは角かっこを使用していません。それはただ:

the_world_is_flat=true
if $the_world_is_flat; then
  echo 'Be careful not to fall off!'
fi

両方のコードスニペットは同じように動作しますが、ブラケットは内部で行われていることを完全に変更します。

それぞれのケースでBashが行っていることは次のとおりです。

括弧なし:

  1. 変数を展開します $the_world_is_flatを文字列に展開します"true"
  2. 文字列を解析しようとする "true"をコマンドとして。
  3. 見つけて実行する trueコマンド(組み込みまたは/bin/trueBashのバージョンに応じて)。
  4. の終了コードを比較します trueコマンドの(常に0)を0とほとんどのシェルでは、終了コード0は成功を示し、それ以外は失敗を示します。
  5. 終了コードが0(成功)だったので、ifステートメントのthen句を実行します

ブラケット:

  1. 変数を展開します $the_world_is_flatを文字列に展開します"true"
  2. 完全に拡張された条件式を解析しますstring1 = string2。これはの形式です。=オペレータは、bashの者です文字列比較演算子。そう...
  3. とで文字列比較"true"を行う"true"ます。
  4. はい、2つの文字列は同じだったので、条件の値はtrueです。
  5. ifステートメントのthen句を実行します。

trueコマンドが成功を示す終了コード0を返すため、括弧なしのコードは機能します。の値は、右側の$the_world_is_flat文字列リテラルと同じであるため、括弧で囲まれたコードは機能しますtrue=ます。

要点を理解するために、次の2つのコードスニペットを検討してください。

このコード(root権限で実行した場合)は、コンピューターを再起動します。

var=reboot
if $var; then
  echo 'Muahahaha! You are going down!'
fi

このコードは、「ナイストライ」を出力するだけです。再起動コマンドは呼び出されません。

var=reboot
if [ $var ]; then
  echo 'Nice try.'
fi

更新(2014-04-14)===AFAIKの違いに関するコメントの質問に答えるには、違いはありません。==オペレータは用バッシュ固有の同義語であります=、そして限り私が見てきたように、彼らはすべてのコンテキストでまったく同じに動作します。

ただし、またはで使用されている=および==文字列比較演算子について具体的に話していることに注意してください。私はそれを示唆していないよと互換性があり、どこでも[ ][[ ]]=== bashで。

たとえば、あなたは明らかにして、変数の割り当てを行うことができない==など、var=="foo"(だけでなく技術的にあなたがすることができ、これを行うが、の値はvarなり"=foo"バッシュが見ていないので、==ここでオペレータを、それは見ています=が続く(代入)演算子を、リテラル値="foo"だけになり、"=foo")。

また、けれども===互換性があり、あなたはどのようにそれらのテストが仕事することを心に留めておく必要がありますないあなたの中にそれを使用しているかどうかに依存し[ ]たり[[ ]]、また、オペランドが引用されているかどうかに。詳細については、「高度なBashスクリプトガイド:7.3その他の比較演算子=およびの説明までスクロールしてください==)」を参照してください。


無ブラケットのアプローチは、あなたのようなクリーン、クリアな(IMO)ワンライナー書き込みせることの利点がある$the_world_is_flat && echo "you are in flatland!"
AJK

9
本当です。しかし、私はどちらのアプローチについても(または反対して)擁護していません。ここで投票されているいくつかの誤った情報を片付けたかったので、後でこのトピックに出くわした人々が、このすべてがどのように機能するかについての多くの誤解を免れないようにします。
Mike Holt

1
混乱の理由は、ミクの元の答えが4年間だったからです。ビルトインへのすべての参照trueは、元の回答に関して行われました。(2014年2月12日の修正された回答は、mikuから提出されませんでした。)私は、オリジナルと修正の両方を含むように回答を編集しました。それから人々のコメントは理にかなっています。
wisbucky 2015年

1
ここで提供されている回答を読むと、実際にを使用するようなものはないという印象を受けtrueます。方法はありますか?私は、この答えを表示する言語を厳しくしbashて生活を少し楽にするためにいくつかの接着剤を混ぜ合わせるのに役立つプログラマーの多くが===、文字列と「ブール値」が実際には交換可能でない演算子を必要とするのではないかと思います。彼らは単に0と1に固執し(( $maybeIAmTrue ))Quonelの質問回答で提案されているように使用する必要がありますか?
SeldomNeedy 2015

2
SeldomNeedyのコメントに対処するには、はい、実数を使用できますがtrue、実数trueはそれ自体に値を持たないため、変数と比較するものとしては使用できません。終了ステータスをに設定するだけで0、成功を示します。これはいわゆる「nullコマンド」またはと本質的に同等であることは注目に値します:0and を使用する限り、1ブール値を必要とする最近のすべてのスクリプトでそれを行っています。そして、評価する(( ))代わりに演算子を使用してい[[ ]]ます。たとえば、私が持っている場合flag=0、私はそれを行うことができますif (( flag )); then ...
Mike Holt

57

算術式を使用します。

#!/bin/bash

false=0
true=1

((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true

出力:


偽ではなく真


3
長所:(1.)動作はCのブール値の処理方法に似ています。(2。)構文は非常に簡潔/最小限です(右側の変数や '='や '=='などの演算子は必要ありません)、(3 。)<subjective>私にとっては、長い説明なしで何が起こるか理解しています...長い説明が必要と思われるMikuとDennisの回答とは対照的です</ subjective>
Trevor Boyd Smith

3
@TrevorBoydSmithなぜ「長所:すべて、短所:何もない」とだけ言わなかったのですか。長期的には、キーボードとモニターの減価償却費を節約できます。
Quolonelの質問

4
ワンライナーのようにインタラクティブに使用する場合は、の後!にスペースを残してください。そうしないと、履歴が拡張されます。 ((! foo))動作し! ((foo))ます。ところで、私はこのソリューションが大好きです。最後に、ブール変数を実行する簡潔な方法です。 ((foo || bar))期待どおりに動作します。
Peter Cordes

5
(())変数を再帰的に展開しますが、これは予期していませんでした。 foo=bar; bar=baz; ((foo)) && echo echo何も出力しませんが、それはに当てはまりますbaz=1。だから、サポートすることができますfoo=trueし、foo=false実行して0または1と同様true=1
Peter Cordes

2
@quolonelは非常に役立つリソースをありがとうございます。もちろん私の理解は限られています-ドメインに関係なくすべての理解が制限されるのは人間の性質です。しかし、私の特定の問題についての私の理解が不完全であるという仮定に導く私の発言のどれを私に教えていただけませんか?
Hubert Grzeskowiak

34

短い話:

Bashにはブール値はありません

Bashには、比較と条件に関してブール式があります。つまり、Bashで宣言して比較できるのは文字列と数値です。それでおしまい。

どこを見てもtruefalseバッシュで、それはどちらかだけの終了コードに使用される文字列またはコマンド/組み込みます。

この構文...

if true; then ...

本質的に...

if COMMAND; then ...

コマンドが終了コード0 trueを返す場合は常に、条件は真です。falseであり、対応する終了コードを返す以外に何もしないBashビルトインおよびスタンドアロンプ​​ログラムの場合もあります。

上記の条件は次と同等です。

COMMAND && ...

大括弧またはtestコマンドを使用するときは、その構成の終了コードに依存します。これは、他のコマンド[ ][[ ]]同様、単なるコマンド/ビルドであることに注意してください。そう ...

if [[ 1 == 1 ]]; then echo yes; fi

に対応

if COMMAND; then echo yes; fi

そしてCOMMANDここは[[ 1 == 1 ]]

if..then..fi構築物は、単に構文糖です。同じ効果を得るには、2つのアンパサンドで区切られたコマンドをいつでも実行できます。

[[ 1 == 1 ]] && echo yes

使用している場合truefalse、これらのテストでは、あなたが実際には文字列を渡している構築"true""false"テスト指令に。次に例を示します。

信じられないかもしれませんが、これらの条件はすべて同じ結果をもたらしています。

if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...

TL; DR; 常に文字列または数値と比較する

これを将来の読者に明確にするために、常に引用符trueとを使用することをお勧めしますfalse

行う

if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...

しない

if [ ... ]; then ...  # Always use double square brackets in bash!
if [[ "${var}" ]]; then ...  # This is not as clear or searchable as -n
if [[ "${var}" != true ]]; then ...  # Creates impression of Booleans
if [[ "${var}" -eq "true" ]]; then ...  # `-eq` is for numbers and doesn't read as easy as `==`

多分

if [[ "${var}" != "true" ]]; then ...  # Creates impression of Booleans. It can be used for strict checking of dangerous operations. This condition is false for anything but the literal string "true".

私はこれらを使用TFて、それらが実際のブール値ではないことを明確にすることを好みます。
phk

1
「bashでは常に二重括弧を使用する」には同意できません。実際、私が書いたほとんどすべてのスクリプトでは、パターンマッチングを行う必要がある場合を除いて、単一の角かっこを使用しています。[test)との違いを理解し、[[彼のニーズに適したものを使用する必要があると思います。
Weijun Zhou

@WeijunZhouは、どの場合に単一のブラケットの方が優れているか詳しく説明しますか?
Hubert Grzeskowiak

それはもっと個人的な好みです。「bashでは常に二重の角かっこを使用する」と言うのが大胆すぎることに気づきました。しかし、私が使用したいくつかのエッジケースがあります。単一の角括弧を使用すると、varでテスト自体を指定できます。単純化の例として、考えるif ....; then mytest='-gt'; else mytest='-eq'; fi; #several lines of code; if [ "$var1" "$mytest" "$var2" ]; then ...; fi
Weijun周

@WeijunZhouあなたの例は、単一の角括弧に対する強力な議論です。これにより、コードの理解がはるかに困難になり、エラーが発生するウィンドウが大きく開きます。二重括弧はより厳格であり、よりクリーンなコードを推奨します。
Hubert Grzeskowiak

18

ずっと前に、私たちが持っていたのはsh、ブールの場合、testプログラムの規則に依存することで処理されましたtest値は、引数なしで実行した場合に偽の終了ステータスを返す。

これにより、未設定の変数をfalseと見なし、変数を任意の値に設定したものをtrueと見なすことができます。現在、testはBashに組み込まれており、一般にその1文字のエイリアス[(またはドルメンが指摘しているように、それを持たないシェルで使用する実行可能ファイル)で知られています。

FLAG="up or <set>"

if [ "$FLAG" ] ; then
    echo 'Is true'
else
    echo 'Is false'
fi

# Unset FLAG
#    also works
FLAG=

if [ "$FLAG" ] ; then
    echo 'Continues true'
else
    echo 'Turned false'
fi

引用規則のため、スクリプト作成者は[[を模倣する複合コマンドを使用することを好みtestますが、構文はより優れています。スペースを含む変数は引用符で囲む必要はありません。1を使用することができます&&し、||変な優先順位の論理演算子として、および用語の数にはPOSIXの制限はありません。

たとえば、FLAGが設定されていて、COUNTが1より大きい数値であるかどうかを判断するには、次のようにします。

FLAG="u p"
COUNT=3

if [[ $FLAG  && $COUNT -gt '1' ]] ; then
    echo 'Flag up, count bigger than 1'
else
    echo 'Nope'
fi

スペース、長さ0の文字列、null変数がすべて必要な場合や、スクリプトが複数のシェルで動作する必要がある場合にも、このことは混乱する可能性があります。


3
[は単なるのエイリアスではありませんbash。このエイリアスは、バイナリファイル(またはそれを指すリンク)としても存在し、bareで使用できますsh。確認してくださいls -l /usr/bin/\[bash/ zshあなたの代わりに使用すべき[[ことは、真の純粋な内部にあり、はるかに強力です。
ドルメン

1
@dolmen [testでもバッシュシェルの組み込みコマンドはBashのマニュアルページによると、その性能に問題があってはなりません。たとえばダッシュと同じです。(/ bin / shは/ bin / dashへのシンボリックリンクにすぎません)。実行可能ファイルを使用するには、フルパス、つまりを使用する必要があります /usr/bin/\[
jarno 2016年

12

シェルスクリプトでブール変数を宣言して使用するにはどうすればよいですか?

他の多くのプログラミング言語とは異なり、Bashは変数を「タイプ」で分離しません。[1]

したがって、答えはかなり明確です。Bashにはブール変数はありません。

しかしながら:

declareステートメントを使用して、変数への値の割り当てを制限できます。[2]

#!/bin/bash
declare -ir BOOL=(0 1) # Remember BOOL can't be unset till this shell terminates
readonly false=${BOOL[0]}
readonly true=${BOOL[1]}

# Same as declare -ir false=0 true=1
((true)) && echo "True"
((false)) && echo "False"
((!true)) && echo "Not True"
((!false)) && echo "Not false"

およびのrオプションは、変数が読み取り専用であることを明示的に示すために使用されます。目的が明確になればいいのですが。declarereadonly


1
どうしてやらないのdeclare -ir false=0 true=1?配列を使用する利点は何ですか?
ベンジャミンW.

@BenjaminW。私はrオプションとreadonlyコマンドについて言及したかっただけです。私がスクリプトで提案した方法でそれを行います
sjsam '30

多分私は何かを逃したが、なぜこのように宣言された真と偽がドル記号を使用しないのですか?$ true $ false
qodeninja

文字通りちょうど私の答えをコピーし、それを悪化させます。
Quolonelの質問

@QuolonelQuestions Bash変数は型指定されていないため、言っても意味がありません。declare and use boolean variables複数の方法で、変数にがあることを模倣/仮定することができます 。私はあなたの答えのどこにも言及されているのを見ませんでした。
sjsam

10

ブール値を偽造して将来の読者に罠をかけずに、trueとfalseよりも優れた値を使用してみませんか?

例えば:

build_state=success
if something-horrible; then
  build_state=failed
fi

if [[ "$build_state" == success ]]; then
  echo go home; you are done
else
  echo your head is on fire; run around in circles
fi

なぜ整数ではないのですか?
phil294 2017

3
@Blauhirn整数は言語によって使用方法が異なるため。いくつかの言語で0強制的に変換するfalse1しますtrue。プログラムの終了コード(bashは歴史的に使用しています)に関しては、それは0肯定的な結果のためでtrueあり、それ以外はすべて否定的/エラーまたはfalseです。
Hubert Grzeskowiak 2017年

7

POSIX(ポータブルオペレーティングシステムインターフェイス)

ここで重要なのは移植性です。そのため、私のヘッダーにはPOSIX自体が含まれています。

基本的に、投票された回答はすべて正しいですが、例外はBash固有のものです。

基本的に、移植性に関する情報を追加したいだけです。


  1. [およびの]ような括弧[ "$var" = true ]は不要であり、省略してtestコマンドを直接使用できます。

    test "$var" = true && yourCodeIfTrue || yourCodeIfFalse

    重要な注意:これは徐々に廃止される予定であり、複数のステートメントを組み合わせることがより困難であるため、これお勧めしません。

  2. それらの単語truefalseシェルにとっての意味を想像して、自分でテストしてください:

    echo $(( true ))
    0
    echo $(( false ))
    1

    しかし、引用符を使用します:

    echo $(( "true" ))
    bash: "true": syntax error: operand expected (error token is ""true"")
    sh (dash): sh: 1: arithmetic expression: expecting primary: ""true""

    同じことが当てはまります:

    echo $(( "false" ))

    シェルは文字列以外は解釈できません。引用符なしで適切なキーワード使用することの効果を理解していただければ幸いです。

    しかし、以前の回答では誰もそれを述べていませんでした。

  3. これは何を意味するのでしょうか?まあ、いくつかのこと。

    • ブールキーワードは実際には数値のように扱われることに慣れる必要があります。つまり、true= 0およびfalse= です。1ゼロ以外のすべての値はのように扱われることに注意してくださいfalse

    • それらは数値として扱われるので、それらもそのように扱う必要があります。つまり、変数を定義する場合は、次のようにします。

      var_bool=true
      echo "$var_bool"
       true

      あなたはそれの反対の値を作成することができます:

      var_bool=$(( 1 - $var_bool ))  # same as $(( ! $var_bool ))
      echo "$var_bool"
      1

    ご存じのとおり、シェルはtrue文字列を初めて使用するときに文字列を出力しますが、それ以降はすべて数値0表現trueまたは1表現falseによってそれぞれ機能します。


最後に、そのすべての情報をどうするか

  • まず、良い習慣はの0代わりに割り当てることですtrue1の代わりにfalse

  • 2番目の適切な習慣は、変数が/がゼロでないかどうかをテストすることです。

    if [ "$var_bool" -eq 0 ]; then
         yourCodeIfTrue
    else
         yourCodeIfFalse
    fi

6

構文に関しては、これは私が(例として)ブール論理を一貫して健全に管理するために使用する単純な方法論です。

# Tests
var=
var=''
var=""
var=0
var=1
var="abc"
var=abc

if [[ -n "${var}" ]] ; then
    echo 'true'
fi
if [[ -z "${var}" ]] ; then
    echo 'false'
fi

# Results
# var=        # false
# var=''      # false
# var=""      # false
# var=0       # true
# var=1       # true
# var="abc"   # true
# var=abc     # true

変数が宣言されていない場合、答えは次のとおりです。 # false

したがって、(この構文方法論を使用して)変数をtrueに設定する簡単な方法はvar=1、逆に、var=''

参照:

-n = var文字列の長さがゼロ以外の場合は真。

-z = var stringの長さがゼロの場合は真。


5

多くのプログラミング言語では、ブール型は整数のサブタイプであるか、または整数サブタイプとして実装され、次のtrueよう1false動作し0ます。

数学的には、ブール代数は2を法とする整数演算に似ています。したがって、言語がネイティブのブール型を提供しない場合、最も自然で効率的な解決策は整数を使用することです。これはほとんどすべての言語で機能します。たとえば、Bashでは次のことができます。

# val=1; ((val)) && echo "true" || echo "false"
true
# val=0; ((val)) && echo "true" || echo "false"
false

man bash

((式))

式は、以下の算術評価で説明されているルールに従って評価されます。式の値がゼロ以外の場合、戻り状況は0です。それ以外の場合、戻りステータスは1です。これは、let「式」とまったく同じです。


5

ビルパーカーは、彼の定義が通常のコード規則とは逆になっているため、反対票を投じています。通常、trueは0として定義され、falseはゼロ以外として定義されます。1はfalseで機能し、9999や-1でも機能します。関数の戻り値についても同じです。0は成功、0以外は失敗です。申し訳ありませんが、投票したり、彼に直接返信したりするための信頼性はまだありません。

Bashは、現在、シングルブラケットの代わりにダブルブラケットを使用することを推奨しており、Mike Holtが提供したリンクは、それらの機能の違いを説明しています。7.3。その他の比較演算子

1つには、-eq数値演算子であるため、コード

#**** NOTE *** This gives error message *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then

整数式を期待して、エラーステートメントを発行します。どちらも整数値ではないため、これはどちらのパラメーターにも適用されます。それでも、二重の角かっこで囲むと、エラーステートメントは発行されませんが、誤った値が生成されます(可能な置換の50%で)。[[0 -eq true]] =成功と評価されますが、[[0 -eq false]] =成功と評価されます。これは誤りです(hmmm ...組み込みの数値はどうですか?)。

#**** NOTE *** This gives wrong output *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then

同様に誤った出力を与える条件の他の順列があります。基本的に、変数を数値に設定してtrue / falseビルトインと比較する、または変数をtrue / falseビルトインに設定して数値と比較するもの(上記のエラー条件以外)。また、変数を組み込みのtrue / falseに設定し、を使用して比較を行うもの-eq。そのため-eq、ブール比較の場合は避け、ブール比較の場合は数値を使用しないでください。無効な結果をもたらす順列の概要は次のとおりです。

# With variable set as an integer and evaluating to true/false
# *** This will issue error warning and not run: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then

# With variable set as an integer and evaluating to true/false
# *** These statements will not evaluate properly: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
#
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" == true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then


# With variable set as an true/false builtin and evaluating to true/false
# *** These statements will not evaluate properly: *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = 0 ]; then
#
if [[ "${The_world_is_flat}" = 0 ]]; then
#
if [ "${The_world_is_flat}" == 0 ]; then
#
if [[ "${The_world_is_flat}" == 0 ]]; then

では、何が機能するのかを見てみましょう。比較と評価の両方にtrue / falseビルトインを使用します(Mike Huntが指摘したように、それらを引用符で囲まないでください)。次に、単一または二重の等号(=または==)と、単一または二重の角括弧([]または[[]])を使用します。個人的には、他のプログラミング言語での論理比較を思い出させる二重等号と、タイピングが好きだからといって二重引用符が好きです。したがって、これらは機能します:

# With variable set as an integer and evaluating to true/false
# *** These statements will work properly: *****
#
The_world_is_flat=true/false;
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then

そこにあります。


2
true/ false組み込み関数は特にで、(いくつかのエディタの構文の強調表示が意味するものではありかもしれないものを無視する)、ここで使用されていない[…]あなたがここに単純な文字列(へのパラメータとして指定されたものと考えることができます例[コマンド)。
2

あなたはそれを今持っています。
Peter Mortensen、

4

私の調査結果と提案は他の投稿とは少し異なります。「フープジャンプ」が提案されていなくても、基本的に「ブール」を「通常の」言語と同じように使用できることがわかりました...

[]明示的な文字列比較は必要ありません...複数のLinuxディストリビューションを試しました。Bash、Dash、およびBusyBoxをテストしました。結果は常に同じでした。最初に投票された投稿が何について話しているのかわかりません。たぶん時代は変わったし、それで全部ですか?

変数をtrueに設定すると、その後、条件内で「肯定的」と評価されます。これをfalseに設定すると、評価は「負」になります。とても簡単です!唯一の注意点は、未定義の変数もtrueのように評価されることです。。(ほとんどの言語でそうであるように)反対のことをするのは良いことですが、それはトリックです- ブール値を明示的にtrueまたはfalseに初期化する必要があるだけです

なぜこのように機能するのですか?その答えは2つあります。A)シェルでのtrue / falseは、実際には「エラーなし」と「エラー」を意味します(つまり、0とその他すべて)。B)true / falseは値ではなく、シェルスクリプトのステートメントです!2番目の点については、実行中trueまたはfalse行自体で、現在のブロックの戻り値をその値に設定します。つまりfalse、「エラーが発生しました」の宣言であり、trueはそれを「クリア」します。変数への割り当てでそれを使用すると、それが変数に「返されます」。アン未定義変数のような評価するtrue条件にそれが均等に0又は「ノーエラーに遭遇」を表すからです。

以下のBash行の例と結果を参照してください。確認したい場合は、自分でテストしてください...

#!/bin/sh

# Not yet defined...
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

myBool=true
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

myBool=false
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

収量

when set to
it evaluates to true
when set to true
it evaluates to true
when set to false
it evaluates to false


1

これは、ショートハンドの実装ですif true

# Function to test if a variable is set to "true"
_if () {
    [ "${1}" == "true" ] && return 0
    [ "${1}" == "True" ] && return 0
    [ "${1}" == "Yes" ] && return 0
    return 1
}

例1

my_boolean=true

_if ${my_boolean} && {
    echo "True Is True"
} || {
    echo "False Is False"
}

例2

my_boolean=false
! _if ${my_boolean} && echo "Not True is True"

はい、機能分解は過小評価されています。
Peter Mortensen、

1

既存の回答は混乱を招きました。

個人的には、Cのように見えて動作するものを持ちたいだけです。

このスニペットは、本番環境で1日に何度も機能します。

snapshotEvents=true

if ($snapshotEvents)
then
    # Do stuff if true
fi

みんなを幸せに保つために、私はテストしました:

snapshotEvents=false

if !($snapshotEvents)
then
    # Do stuff if false
fi

これもうまくいきました。

$snapshotEvents変数の値の内容を評価します。だからあなたは必要$です。

かっこは本当に必要ないので、助かると思います。

  • テスト済み:GNU Bash、バージョン4.1.11(2)-release

  • Bash Guide for Beginners、Machtelt Garrels、v1.11、2008


2
かっこを削除すると、これはまさに@mikuの最初の元の答えです。
ドルメン

1
括弧がないと、式は評価されません。
意志

@はいそうです。()は必要ありません。
phil294 2017年

1
@Blauhirn ...こんにちは、私のコメントは、Linux Mint / Ubuntu PCでのGNU Bashの実験に基づいています。あなたはおそらく理論的に 正しい()-sは必要ありません。私の唯一の反応は、試してみることです。それは、Bashのバージョン、実際の表現やコンテキストなどに依存しているようです。
意志

1

変数が設定されていない場合のDennis Williamsonの懸念に対処する、mikuの元の回答の改善点を次に示します。

the_world_is_flat=true

if ${the_world_is_flat:-false} ; then
    echo "Be careful not to fall off!"
fi

そして、変数がfalse次のとおりかどうかをテストします。

if ! ${the_world_is_flat:-false} ; then
    echo "Be careful not to fall off!"
fi

変数に不快なコンテンツが含まれる他のケースについては、これはプログラムに供給される外部入力の問題です。

外部入力は、信頼する前に検証する必要があります。しかし、その検証は、その入力を受け取ったときに一度だけ実行する必要があります。

Dennis Williamsonが示唆するように、変数を使用するたびにそれを実行することで、プログラムのパフォーマンスに影響を与える必要はありません。


1

shFlagsを使用できます。

定義するオプションを提供します。 DEFINE_bool

例:

DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");

コマンドラインから、次のものを定義できます。

sh script.sh --bigmenu
sh script.sh --nobigmenu # False

GFlagsはこの答えでは意味がありません-これはC ++ライブラリです。シェルスクリプトで直接使用することはできません。
ジョナサンクロス

シェルへのGFlagsのポートであるshFlagsへの応答を更新しました。
gogasca

0

これは、Bashで「ブール」値をテストするさまざまな方法に関する速度テストです。

#!/bin/bash
rounds=100000

b=true # For true; b=false for false
type -a true
time for i in $(seq $rounds); do command $b; done
time for i in $(seq $rounds); do $b; done
time for i in $(seq $rounds); do [ "$b" == true ]; done
time for i in $(seq $rounds); do test "$b" == true; done
time for i in $(seq $rounds); do [[ $b == true ]]; done

b=x; # Or any non-null string for true; b='' for false
time for i in $(seq $rounds); do [ "$b" ]; done
time for i in $(seq $rounds); do [[ $b ]]; done

b=1 # Or any non-zero integer for true; b=0 for false
time for i in $(seq $rounds); do ((b)); done

それは次のようなものを印刷します

true is a shell builtin
true is /bin/true

real    0m0,815s
user    0m0,767s
sys     0m0,029s

real    0m0,562s
user    0m0,509s
sys     0m0,022s

real    0m0,829s
user    0m0,782s
sys     0m0,008s

real    0m0,782s
user    0m0,730s
sys     0m0,015s

real    0m0,402s
user    0m0,391s
sys     0m0,006s

real    0m0,668s
user    0m0,633s
sys     0m0,008s

real    0m0,344s
user    0m0,311s
sys     0m0,016s

real    0m0,367s
user    0m0,347s
sys     0m0,017s

-2

代替-関数を使用する

is_ok(){ :;}
is_ok(){ return 1;}
is_ok && echo "It's OK" || echo "Something's wrong"

関数の定義は直感的ではありませんが、戻り値の確認は非常に簡単です。


1
これはテストできる変数ではなく、定数関数です
jarno

@jarnoスクリプトの目的で、関数の戻り値のテストは変数のテストとは異なりますか?
johnraff

さて、問題は変数についてです。
jarno

正しいですが、シェルスクリプトでの使用法は同じです。
johnraff

-2

バッシュは本当にの同類の問題を混乱[[[(($((、など

すべてがお互いのコードスペースを踏みにじっています。これは主に歴史的なもので、Bashがsh時折ふりをしなければならなかったと思います。

ほとんどの場合、私は方法を選んでそれを使い続けることができます。この例では、宣言する傾向があります(できれば.、実際のスクリプトに含めることができる一般的なライブラリファイルで)。

TRUE=1; FALSE=0

次に((... ))算術演算子を使用して、このようにテストできます。

testvar=$FALSE

if [[ -d ${does_directory_exist} ]]
then
    testvar=$TRUE;
fi

if (( testvar == TRUE )); then
    # Do stuff because the directory does exist
fi
  1. あなたはしつけられる必要があります。あなたのtestvar必見は、いずれかに設定する$TRUEか、$FALSEすべての回で。

  2. ((... ))コンパレータ、あなたは、先行する必要はありません$、それは読みやすくています。

  3. and 、つまり数値なので((... を使用できます。))$TRUE=1$FALSE=0

  4. 欠点は、$時々使用する必要があることです:

    testvar=$TRUE

    それはそれほどきれいではありません。

これは完璧な解決策ではありませんが、このようなテストに必要なすべてのケースをカバーします。


2
定数は読み取り専用で宣言する必要があります。また、変数を使用するときは常に中括弧を使用してください。それは誰もが私見に固執すべき慣習です。このソリューションの大きな欠点は、代数式とテストフラグまたは文字列比較を混在させることができないことです。
Hubert Grzeskowiak 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.