web-dev-qa-db-ja.com

シェルスクリプトでブール変数を宣言して使用する方法

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

variable=$false

variable=$true

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

if [ $variable ]

if [ !$variable ]
775
hassaanm

修正された回答(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日の改訂前のコメントは元の回答にのみ関連しており、改訂された回答に関連すると多くのコメントが間違っているためです。 2010年6月2日のbash組み込みtrueについては、元の回答にのみ適用され、改訂版には適用されません。

900
miku

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

通常、あなたの "boolean"変数、この例では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の最初の答えについてのMike Holtの説明も参照。

Hbar's answerの問題

このアプローチも予期しない動作をします。

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または[を使用しても違いはありません。

私がすべきこと:

あなたの "booleans"をチェックすることをお勧めします。期待どおりに動作します。

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. Mikuの答えはそれ以来編集され、もはや(既知の)欠陥を含んでいません。
  2. 網羅的なリストではありません。
  3. この文脈で有効なコマンドは、存在するコマンドを意味します。コマンドが正しく使用されても誤って使用されても問題ありません。例えば。そのようなmanページが存在しなくても、man womanは有効なコマンドと見なされます。
  4. 無効な(存在しない)コマンドについては、Bashは単にそのコマンドが見つからなかったと文句を言います。
  5. あなたが長さを気にするならば、最初の推奨は最短です。
657
Dennis

ここでは、Bashの組み込みtrueについて、さらに具体的には、Bashが括弧内の式を展開して解釈する方法について、いくつかの誤解があるようです。

miku's answer のコードは、Bashの組み込みtrue/bin/true、その他のtrueコマンドとはまったく関係ありません。この場合、trueは単なる文字列に過ぎず、変数の割り当てや条件式の評価のいずれでも、trueコマンド/組み込み関数の呼び出しは行われません。

次のコードは、mikuの回答のコードと機能的に同じです。

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

ここでのonlyの違いは、比較される4文字が「t」ではなく「y」、「e」、「a」、「h」であることです'、' r '、' u '、および' e '。それでおしまい。 yeahという名前のコマンドまたはビルトインを呼び出そうとしたり、Bashがトークンtrueを解析する際に特別な処理を行ったりすることはありません(mikuの例では)。これは単なる文字列であり、完全に任意の文字列です。

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

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

両方のコードスニペットはbehaveと同じ方法ですが、括弧は内部で行われていることを完全に変更します。

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

括弧なし:

  1. 変数$the_world_is_flatをストリング"true"に展開します。
  2. 文字列"true"をコマンドとして解析しようとしました。
  3. trueコマンド(Bashのバージョンに応じて、組み込みまたは/bin/trueのいずれか)を見つけて実行します。
  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)===の違いに関するコメントの質問に答えるには、違いはありません。 ==演算子は、=のBash固有の同義語であり、私が見た限りでは、すべてのコンテキストでまったく同じように機能します。

ただし、=または==テストで使用される[ ]および[[ ]]文字列比較演算子について具体的に説明していることに注意してください。 ===が交換可能であることを示唆しているわけではありませんeverywhereのbashです。

たとえば、==などのvar=="foo"を使用した変数の割り当ては明らかにできません(技術的にはcanですが、Bashには"=foo"演算子が表示されないため、varの値は==になります)ここでは、=(割り当て)演算子に続いて、リテラル値="foo"が続きます。これは、単に"=foo"になります)。

また、===は互換性がありますが、これらのテストの動作方法doesは、[ ]または[[ ]]内でテストを使用するかどうか、およびオペランドが引用符で囲まれているかどうかに依存することに注意してください。詳細については高度なBashスクリプトガイド:7.3その他の比較演算子=および==の説明までスクロールしてください)で読むことができます。

153
Mike Holt

算術式を使用してください。

#!/bin/bash

false=0
true=1

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

出力:

本当の
偽ではない

42

短い話:

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

Bashが持っているのは、比較と条件の点でブール式です。そうは言っても、bashで宣言し比較できるのは文字列と数値です。それでおしまい。

truename__またはfalsename__がbashで表示されているところはどこでも、その終了コードにのみ使用されるストリングまたはコマンド/組み込みのいずれかです。

この構文は...

if true; then ...

本質的には...

if COMMAND; then ...

コマンドが終了コード0を返すときはいつでも条件は真です。truename__とfalsename__はBashの組み込みであり、時には対応する終了コードを返す以外に何もしないスタンドアロンプ​​ログラムです。

上記の条件は、以下と同等です。

COMMAND && ...

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

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

に対応

if COMMAND; then echo yes; fi

そしてCOMMANDname__はここで[[ 1 == 1 ]]です

if..then..fi構文は単なる構文上の糖です。同じ効果を得るために、コマンドをダブルアンパサンドで区切って実行するだけです。

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

これらのテスト構成でtruename__およびfalsename__を使用するときは、実際にはストリング"true"または"false"をテストコマンドに渡すだけです。ここに例があります:

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

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

TL; DR;常に文字列や数値と比較する

これを将来の読者に明確にするために、私は常にtruename__およびfalsename__を引用符で囲むことをお勧めします。

行う

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. Can be used for strict checking of dangerous operations. This condition is false for anything but the literal string "true". 
20

昔、shしかなかったとき、testプログラムの規則に基づいて処理されるブール値は、引数なしで実行するとtestがfalse終了ステータスを返します。これにより、設定されていない変数がfalseであり、変数の値がtrueであると考えることができます。現在、テストは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を模倣するより良い構文を持つ複合コマンド[[を使用することを好みます。スペースを含む変数は引用符で囲む必要はありません。&&および||奇妙な優先順位を持つ論理演算子として。用語の数に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

このようなものは混乱を招く可能性があります スペース、長さゼロの文字列、null変数がすべて必要な場合、およびスクリプトが複数のシェルで動作する必要がある場合。

16
Hbar

シェルスクリプトでブール変数を宣言して使用する方法

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

だから答えはかなり明らかです。 bashにboolean variableはありません。ただし、

宣言ステートメントを使用して、値の割り当てを変数に制限することができます。 [2]

#!/bin/bash
declare -ir BOOL=(0 1) #remember BOOL can't be unset till this Shell terminate
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"

rdeclarereadonlyオプションは、変数が readonly であることを明示的に示すために使用されます。目的が明確であることを願っています。

11
sjsam

ブール値を偽造して将来の読者のための罠を残す代わりに、なぜ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
6
Pyrolistical

Bill Parkerは、通常のコード規約とは定義が逆になっているため、 に投票されています。通常、trueは0として定義され、falseはゼロ以外として定義されます。関数の戻り値 - 0は成功、0以外は失敗です申し訳ありませんが、投票や直接返事をすることはできません。

Bashは、シングルブラケットの代わりにダブルブラケットを習慣として使用することを推奨します。MikeHoltが与えたリンクは、それらがどのように機能するかの違いを説明しています。7.3。その他の比較演算子

一つには、-eqは数値演算子なので、コードは

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

整数式を期待してエラーステートメントを発行します。どちらも整数値ではないため、これはどちらのパラメータにも当てはまります。しかし、二重括弧を囲むと、エラーステートメントは発行されませんが、間違った値になります(可能な順列の50%)。 [[0 -eq true]] = successと評価されますが、[[0 -eq false]] = successと評価されますが、これは間違っています(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

そこにあります。

3
Randyman99

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

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

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

man bash

((式))

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

2
Cyker

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

ここで重要なポイント、つまり移植性が欠けています。それが私のヘッダが _ posix _ を持つ理由です。

基本的に、投票された答えはすべて正解ですが、例外として、 _ bash _ - 固有のものが多すぎます。

したがって、基本的には、移植性についての情報を追加したいだけです。


  1. [のように][ "$var" = true ]の括弧は必要ありません。それらを省略してtestコマンドを直接使用することができます。

    test "$var" = true && CodeIfTrue || CodeIfFalse
    
  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_a=true
      echo "$var_a"
      
       true
      

      逆の値を作成することができます:

      var_a=$((1 - $var_a))
      echo "$var_a"
      
      1
      

      ご存じのように、Shellはtrueという文字列を初めて使用するときには印刷しますが、それ以降は、それぞれ番号0または1を介して機能します。


最後に、あなたがそのすべての情報を使ってすべきこと

  • 最初の良い習慣はtrueの代わりに0を割り当てることです。 falseではなく1

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

    test "$var" -eq 0 && CodeIfTrue || CodeIfFalse
    
2
Vlastimil

これは短い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"
1
llundin

これが私のために働く簡単な例です:

temp1=true
temp2=false

if [ "$temp1" = true ] || [ "$temp2" = true ]
then
    echo "Do something." 
else
    echo "Do something else."
fi

これはmikuの 元の答え を改良したものです。これは Dennis Williamson が変数が設定されていない場合についての懸念に対処します。

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 のように変数を使用するたびにプログラムの実行に影響を与える必要はありません。

0
dolmen

私は既存の答えが分かりにくいと感じました。

個人的には、Cのように見えて動作するものが欲しいのです。

このスニペットは、プロダクションで1日に何度でも動作します。

snapshotEvents=true

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

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

snapshotEvents=false

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

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

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

あなたは本当に括弧を必要としません、私はそれらが役に立つと思います。

0
will

私の調査結果と提案は他の記事とは少し異なります。私は基本的に「フープジャンプ」が示唆されることなしに、「普通の」言語のようにtrue/falseを使うことができることを知りました。 bash、ダッシュ、およびbusybox。私は彼女が強打してもしなくても走った…結果はいつも同じだった。元のトップ投票投稿が何について話しているのかわかりません。たぶん時代は変わった、そしてそれはそれにあるすべてであるか?

変数をtrueに設定すると、条件付きではtrueと評価されます。それをfalseに設定すると、falseと評価されます。とても簡単です。唯一の注意点は、 _ undefined _ 変数も true !と評価されることです。それが逆であればいいでしょうが、それはトリック - あなたは単にブール値をtrueまたはfalseに明示的に設定する必要があります

下記の例の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
0
BuvinJ

GFlagsを使用できます。 https://gflags.github.io/gflags/

以下を定義するオプションを提供します:DEFINE_bool

例:

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

コマンドラインから以下を定義できます:

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