1241

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

variable=$false

variable=$true

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

if [ $variable ]

if [ !$variable ]
4

23 に答える 23

1502

改訂された回答 (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 builtin に関する Dennis Williamson のコメントは、元の回答にのみ適用され、改訂版には適用されません。

于 2010-06-01T21:58:55.187 に答える
993

TL;DR

my_bool=true

if [ "$my_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 の元の回答に関する Mike Holt の説明も参照してください。

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

推奨すること:

「ブール値」を確認することをお勧めする方法を次に示します。それらは期待どおりに機能します。

my_bool=true

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

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

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

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


脚注

  1. ミクの回答はその後編集され、(既知の) 欠陥は含まれなくなりました。
  2. 網羅的なリストではありません。
  3. このコンテキストで有効なコマンドとは、存在するコマンドを意味します。コマンドの使い方が正しいか間違っているかは問題ではありません。たとえばman woman、そのような man ページが存在しない場合でも、有効なコマンドと見なされます。
  4. 無効な (存在しない) コマンドの場合、Bash は単にコマンドが見つからなかったと文句を言います。
  5. 長さを気にするなら一番最初におすすめするのは最短です。
于 2014-01-18T22:57:46.523 に答える
194

ここでは、Bash builtin について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

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

更新 (2014-02-19): miku の回答のリンクをたどった後、混乱の原因がどこから来ているかがわかります。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を string に展開します"true"
  2. "true"文字列をコマンドとして解析しようとします。
  3. コマンドを見つけて実行します( Bash のバージョンに応じてtrue、ビルトインまたは のいずれか)。/bin/true
  4. コマンドの終了コード (常に 0) を 0 と比較しますtrue。ほとんどのシェルでは、終了コード 0 は成功を示し、それ以外は失敗を示すことを思い出してください。
  5. 終了コードが 0 (成功) だったので、ifステートメントのthen句を実行します。

ブラケット:

  1. 変数$the_world_is_flatを string に展開します"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 固有のシノニムで=あり、私が見た限りでは、すべてのコンテキストでまったく同じように機能します。

ただし、ここではorテストで使用される文字列比較演算子=andについて具体的に話していることに注意してください。私はそれを示唆しているのではなく、bash のどこでも交換可能です。==[ ][[ ]]===

たとえば、==(var=="foo"技術的にはこれを行うことができますが、の値はvarになります"=foo"。Bash は==ここで演算子を見ていないため、=(代入) 演算子を見て、その後にに="foo"なるリテラル値"=foo")。

また、=とは互換性がありますが、これらのテスト==どのように機能するかは、または内で使用しているかどうか、およびオペランドが引用符で囲まれているかどうかによって異なることに注意してください。詳細については、Advanced Bash Scripting Guide: 7.3 Other Comparison Operators (との説明まで下にスクロールしてください) を参照してください。[ ][[ ]]===

于 2014-02-13T23:45:15.640 に答える
80

算術式を使用します。

#!/bin/bash

false=0
true=1

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

出力:

真偽で
はない

于 2014-11-13T23:44:32.230 に答える
67

簡単に言えば:

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

trueおよびfalseコマンド_

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

Bash のどこにいてtruefalse、終了コードにのみ使用される文字列またはコマンド/組み込みのいずれかです。

この構文...

if true; then ...

本質的に...

if COMMAND; then ...

コマンドはtrueです。コマンドが終了コード 0trueを返すときはいつでも、条件は true です。falseまた、Bash ビルトインであり、場合によっては、対応する終了コードを返すだけで何もしないスタンドアロン プログラムでもあります。


の条件if..then..fi

角括弧または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

trueこれらのテスト コンストラクトを使用するfalse場合、実際には文字列"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 [[ "${var}" == "yes" ]]; then ...
if [[ "${var}" == "USE_FEATURE_X" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...

しないでください

# Always use double square brackets in bash!
if [ ... ]; then ...
# This is not as clear or searchable as -n
if [[ "${var}" ]]; then ...
# Creates impression of Booleans
if [[ "${var}" != true ]]; then ...
# `-eq` is for numbers and doesn't read as easy as `==`
if [[ "${var}" -eq "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".
if [[ "${var}" != "true" ]]; then ... 
于 2017-11-03T09:54:05.247 に答える
7

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

ここで重要なポイントである移植性を見逃しています。そのため、ヘッダー自体にPOSIXが含まれています。

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

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


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

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

    重要な注意:徐々に非推奨になり、複数のステートメントを組み合わせることがより困難になっているため、これはお勧めしません。

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

    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=0false=です。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ます。


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

  • まず、1 つの良い習慣は;0の代わりに割り当てることです。の代わりに。true1false

  • 2 番目の良い習慣は、変数がゼロに等しくないかどうかをテストすることです。

    if [ "$var_bool" -eq 0 ]; then
         yourCodeIfTrue
    else
         yourCodeIfFalse
    fi
    
于 2018-02-01T17:45:10.137 に答える
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"
于 2018-03-09T13:49:58.503 に答える
-2

Bash は、こ​​の問題を 、 、 、 などと混同し[[[((ます$((

すべてが互いのコード空間を踏みにじる。これは主に歴史的なものだと思います.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. ((...))と、つまり数値$TRUE=1を使用できます。$FALSE=0

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

    testvar=$TRUE
    

    これはあまりきれいではありません。

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

于 2014-10-03T14:36:21.730 に答える