回答:
その理由は-eq
、引数の算術評価が強制されるためです。
算術演算子:-eq
、-gt
、-lt
、-ge
、-le
および-ne
内部[[ ]]
(kshので、zshのおよびBash)自動的に導く必要がC言語のような変数名を展開するための手段$
。
確認のために、bashのソースコードを調べる必要があります。マニュアルでは直接確認することはできません。
test.c
算術演算子の処理の中では、この関数に分類されます。
arithcomp (s, t, op, flags)
どこs
とt
両方のオペランドです。オペランドはこの関数に渡されます。
l = evalexp (s, &expok);
r = evalexp (t, &expok);
この関数evalexp
は、次のexpr.c
ヘッダーを持つ内部で定義されています。
/* expr.c -- arithmetic expression evaluation. */
したがって、はい、算術演算子の両側は算術式の評価に(直接)該当します。直接、no buts、no ifs。
実際には:
$ x=3
両方とも失敗します:
$ [[ x = 4 ]] && echo yes || echo no
no
$ [[ x = 3 ]] && echo yes || echo no
no
どちらが正しいか、x
展開されてx
おらず、数値と等しくない。
しかしながら:
$ [[ x -eq 3 ]] && echo yes || echo no
yes
$ [[ x -eq 4 ]] && echo yes || echo no
no
指定された変数x
は展開されます($がなくても)。
これは[…]
、zshまたはbashで発生しません(kshで発生します)。
それはaの中で起こることと同じ$((…))
です:
$ echo $(( x + 7 ))
10
そして、これは(非常に)再帰的であることを理解してください(ダッシュとyashを除く):
$ a=b b=c c=d d=e e=f f=3
$ echo "$(( a + 7 ))"
10
そして非常に危険です:
$ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
構文エラーは簡単に回避できます。
$ a=3; x='a[$(date -u >/dev/tty; echo 0)]'
$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes
sayingにあるように:入力をサニタイズする
$ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no
😮の終わり
(古い)外部/usr/bin/test
(ビルトインではないtest
)とさらに古い外部の両方は、式を整数のみ(および明らかに10進整数のみ)expr
展開しません。
$ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’
$ expr x + 3
expr: non-integer argument
[[
キーワードであるため、演算子とオペランドは、コマンドが展開された後ではなく読み込まれたときに検出されます。したがって、例えば、よりスマートな方法で[[
扱うことができます。しかし、私が疑問に思うのは、複合コマンドを解釈するためにbashが使用するロジックに関するドキュメントはどこにありますか?それは私には非常に明白に見えないし、私は満足な説明を見つけることが明らかにできないんですか。-eq
[
man
info bash
test
数値比較のオペランドは-eq
、-gt
、-lt
、-ge
、-le
および-ne
演算式として取られます。いくつかの制限はありますが、それらは単一のシェルワードである必要があります。
算術式での変数名の動作は、Shell Arithmeticで説明されています。
シェル変数はオペランドとして使用できます。式が評価される前に、パラメータ展開が実行されます。式内では、パラメータ拡張構文を使用せずにシェル変数を名前で参照することもできます。nullまたは未設定のシェル変数は、パラメーター拡張構文を使用せずに名前で参照すると0と評価されます。
また:
変数の値は、参照されると算術式として評価されます
しかし、数値比較には算術式を使用すると言われているドキュメントの部分は実際には見つかりません。以下の条件付きコンストラクトでは説明されておらず[[
、Bash条件式でも説明されていません。
しかし、実験では、上記のように機能するようです。
したがって、このようなものは動作します:
a=6
[[ a -eq 6 ]] && echo y
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y
これも(変数の値が評価されます):
b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y
しかし、これはそうではありません。[[ .. ]]
が解析されるとき、単一のシェルワードではないため、条件に構文エラーがあります。
[[ 1 + 2 + 3 -eq 6 ]] && echo y
他の算術コンテキストでは、式が空白なしである必要はありません。これは999
、角かっこがインデックス内の算術式を明確に区切るため、を出力します。
a[6]=999; echo ${a[1 + 2 + 3]}
一方、=
比較はパターンマッチであり、算術や算術コンテキストで行われる自動変数展開は含まれません(条件付き構成):
場合
==
や!=
演算子が使用されているextglobシェルオプションが有効になったかのように、オペレータの右側の文字列は、パターンマッチングに説明ルールに従ってパターンとみなされ、一致しています。=
オペレータは同じです==
。
文字列が明らかに異なるため、これはfalseです。
[[ "1 + 2 + 3" = 6 ]]
数値は同じですが、これは次のとおりです。
[[ 6 = 06 ]]
ここでも、文字列(x
と6
)が比較されますが、それらは異なります:
x=6
[[ x = 6 ]]
ただし、これにより変数が展開されるため、次のようになります。
x=6
[[ $x = 6 ]]
arg1 OP arg2
は、引数は正または負の整数である可能性があるということです。これは、算術式として扱われることを意味すると思われます。紛らわしいことに、これはゼロにできないことも意味します。:)
[
も当てはまり、それらは算術式ではありません。代わりに、Bashは非整数について文句を言います。
[
は外部コマンドであり、シェル変数にアクセスできません。多くの場合、組み込みコマンドで最適化されますが、それでも同じように動作します。
はい、あなたの観察は正しいです、変数の展開は二重括弧の下の式で実行される[[ ]]
ので$
、変数名の前に置く必要はありません。
これは、bash
マニュアルに明示的に記載されています。
[[expression]]
(...)単語の分割とパス名の展開は、[[と]]の間の単語では実行されません。チルダ展開、パラメータおよび変数展開、算術展開、コマンド置換、プロセス置換、および引用削除が実行されます。
これは、シングルブラケットバージョンの場合ではないことを通知[ ]
として、[
シェルキーワード(構文)ではなく、コマンド(bashで、それは他のシェルは、外部使用することができ、組み込みであり、テストに並びます)。
(x=1; [[ $x = 1 ]]; echo $?)
Returns 0
、(x=1; [[ x = 1 ]]; echo $?)
returns 1
、つまり、x
文字列を比較するときにパラメータ展開は実行されません。この動作は、算術展開によってトリガーされる算術評価のように見え(x=1; echo $((x+1)))
ます。(算術評価についてman bash
は、「式内では、パラメーター拡張構文を使用せずにシェル変数を名前で参照することもできます」と述べています。
-gt
演算子は数値を想定しているため、内部全体のように式全体が再評価され、(())
一方で==
文字列を想定している代わりにパターンマッチング関数がトリガーされます。私はソースコードを掘り下げたわけではありませんが、理にかなっています。
[
bashに組み込まれたシェルです。
x=1
従うとあなたの評価は変わります[[ x -gt 2]]
か?