次の構文を使用して、シェル スクリプトでブール変数を宣言しようとしました。
variable=$false
variable=$true
これは正しいです?また、その変数を更新したい場合、同じ構文を使用しますか? 最後に、ブール変数を式として使用するための次の構文は正しいですか?
if [ $variable ]
if [ !$variable ]
改訂された回答 (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 のコメントは、元の回答にのみ適用され、改訂版には適用されません。
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 の説明も参照してください。
このアプローチには、予期しない動作もあります。
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のアプローチよりもいくつかのキーストロークを入力する必要がありますが、コードはより防御的になります。
man woman
、そのような man ページが存在しない場合でも、有効なコマンドと見なされます。ここでは、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 が行っていることは次のとおりです。
ブラケットなし:
$the_world_is_flat
を string に展開します"true"
。"true"
文字列をコマンドとして解析しようとします。true
、ビルトインまたは のいずれか)。/bin/true
true
。ほとんどのシェルでは、終了コード 0 は成功を示し、それ以外は失敗を示すことを思い出してください。if
ステートメントのthen
句を実行します。ブラケット:
$the_world_is_flat
を string に展開します"true"
。string1 = string2
。=
演算子は bash の文字列比較演算子です。そう..."true"
行い"true"
ます。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 (との説明まで下にスクロールしてください) を参照してください。[ ]
[[ ]]
=
==
算術式を使用します。
#!/bin/bash
false=0
true=1
((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true
出力:
真偽で
はない
簡単に言えば:
true
およびfalse
コマンド_Bash には、比較と条件に関してブール式があります。とはいえ、Bash で宣言して比較できるのは、文字列と数値です。それでおしまい。
Bash のどこにいてtrue
もfalse
、終了コードにのみ使用される文字列またはコマンド/組み込みのいずれかです。
この構文...
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 ...
将来の読者にこれを明確にするために、 と を常に引用符で囲むことをお勧めし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 ...
ここで重要なポイントである移植性を見逃しています。そのため、ヘッダー自体にPOSIXが含まれています。
基本的に、投票された回答はすべて正しいですが、例外はBash固有のものです。
基本的に、移植性に関する情報を追加したいだけです。
[
の]
ような括弧[ "$var" = true ]
は必要ありません。それらを省略して、test
コマンドを直接使用できます。
test "$var" = true && yourCodeIfTrue || yourCodeIfFalse
重要な注意:徐々に非推奨になり、複数のステートメントを組み合わせることがより困難になっているため、これはお勧めしません。
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" ))
シェルは文字列以外は解釈できません。引用符なしで適切なキーワードを使用することがいかに優れているかを理解していただければ幸いです。
しかし、以前の回答では誰もそれを言いませんでした。
これは何を意味するのでしょうか?さて、いくつかのこと。
ブール値のキーワードが実際には数値のように扱われることに慣れる必要があります。つまり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
ます。
まず、1 つの良い習慣は;0
の代わりに割り当てることです。の代わりに。true
1
false
2 番目の良い習慣は、変数がゼロに等しくないかどうかをテストすることです。
if [ "$var_bool" -eq 0 ]; then
yourCodeIfTrue
else
yourCodeIfFalse
fi
これはショートハンドの実装です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"
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
あなたは規律を持たなければなりません。常にまたはtestvar
に設定する必要があります。$TRUE
$FALSE
((
...コンパレータでは))
、前の は必要ないため、$
読みやすくなります。
((
...))
と、つまり数値$TRUE=1
を使用できます。$FALSE=0
欠点は、$
時々使用する必要があることです。
testvar=$TRUE
これはあまりきれいではありません。
これは完全な解決策ではありませんが、そのようなテストに必要なすべてのケースをカバーしています。