変数を文字列またはintとして比較するときに大きな違いはありますか


22

好奇心から、bash変数の比較(値はinteger)を行う場合、an intまたはaとして宣言された定義済みの値に対してテストできstringます。

サンプルスクリプト

#!/bin/bash
f1()
{
        [ "$1" == "1" ] && echo "$FUNCNAME: \"1\" compared as string"
}

f2()
{
        [[ "$1" -eq 1 ]] && echo "$FUNCNAME: \"1\" compared as int"
}

f1 $1
f2 $1

出力

$  ./param.sh 1
f1: "1" compared as string
f2: "1" compared as int

そして

$  ./param.sh blah
$

両方の関数は同じように動作しますので、整数変数をチェックするときに好ましい方法があるのだろうかと思いますか?私はチェックのために行くだろうintintそれはより厳格だとしてではなくて、それをやって任意のドローバックがあるのだろうかstring

この場合、f2()比較もより厳密になります。つまり、10進数値を渡すと壊れますがf1()、問題はありません。


Bashには実際にはIntegerデータ型がないことに注意してください。基本的に、文字列を整数として扱うようにBashにヒントを与えることができます。
ヘルパーメソッド14

回答:


18

うん、多くの違い。たとえば=、正確な文字列の等価性をチェックしますが、-eq等価性をチェックする前に両方の式を算術的に評価します。

$ [ " 1 " -eq 1 ] && echo equal || echo not
equal
$ [ " 1 " = 1 ] && echo equal || echo not
not

$ [ +1 -eq 1 ] && echo equal || echo not
equal
$ [ +1 = 1 ] && echo equal || echo not
not

$ [ "0+1" -eq 1 ] && echo equal || echo not
equal
$ [ "0+1" = 1 ] && echo equal || echo not
not

また、空の文字列は数値的にゼロに等しくなります。

$ [ "" -eq 0 ] && echo equal || echo not
equal
$ [ "" = 0 ] && echo equal || echo not
not

そして、比較演算子を導入すると、他のクラスの違いが現れます- 例えば、<vsを考慮して-ltください:

$ [[ 2 -lt 10 ]] && echo less || echo not
less
$ [[ 2 < 10 ]] && echo less || echo not
not

これは、文字列 "2"が文字列 "10"の後にアルファベット順である(1は2の前に来るため)が、数値 "2"は数値 "10"よりも小さいためです。


2
(( ... ))数値演算もあることを忘れないでください。(( " 1 " == 1 )) && echo yes || echo no結果yes
パトリック14

7

整数と文字列の比較は、以下よりも大きいまたは小さい場合に最も重要になります。

#!/bin/bash

eleven=11
nine=9

[[ $nine < $eleven ]] && echo string   # fail

[[ "$nine" -lt "$eleven" ]] && echo integer # pass

辞書順でソートされた場合、9が11の後に来るため、最初のものは失敗します。

引用符を使用しても、文字列と数値のどちらを比較するかは決定されないことに注意してください。上記の引用符を追加または削除できますが、違いはありません。Bashは二重括弧内の未定義の変数をキャッチするため、引用符は必要ありません。数値テストに単一の角括弧を含む引用符を使用しても、次の理由からあなたを救うことはできません。

[ "" -lt 11 ]

とにかくエラーです(「整数式が必要」)。引用符は、単一の括弧内の文字列比較による効果的な保護手段です。

[ "" \< 11 ]

内注ダブルブラケット、""意志-eq 0はありません== 0


1
bashでは、変数を二重括弧内に引用することは厳密に必要ではありません:組み込み[[は変数がどこにあるかを記憶するのに十分スマートで、空の変数にだまされません。単一の括弧([)にはこの機能がなく、引用符が必要です。
グレンジャックマン14

@glennjackmanそれに気づかなかった。[[ -lt 11 ]]エラーですが、そうでnothing=; [[ $nothing -lt 11 ]]はありません。最後の段落を少し作り直しました。
goldilocks 14

2

言われたことに加えて。
シェルスクリプトでは、高速な計算が必要になることはまれですが、等しいかどうかを数値で比較すると高速になります。

$ b=234
$ time for ((a=1;a<1000000;a++)); do [[ $b = "234" ]]; done

real    0m13.008s
user    0m12.677s
sys 0m0.312s

$ time for ((a=1;a<1000000;a++)); do [[ $b -eq 234 ]]; done

real    0m10.266s
user    0m9.657s
sys 0m0.572s

それらが異なることを行うことを考えると、パフォーマンスは無関係であると思います-あなたがしたいことをするものを使用する必要があります。
godlygeek 14

@godlygeek変数の等価比較は、両方の方法で実現できます。「-eq」の方が高速です。
エマニュエル14

彼らは平等の異なる定義をテストします。あなたが質問に答えるしたい場合は、「この変数ホールドは正確な文字列123ない」、あなただけ使用することができます=使用しているので、-eq同様に「123」のために一致します。「算術式として評価されたときに、この変数を実行し、123に等しいと比較する」ことを知りたい場合は、のみを使用できます-eq。プログラマーがどの等値の定義が使用されるかを気にかけないのは、変数の内容が事前に特定のパターンに制約されていることを知っているときだけです。
godlygeek 14

@godlygeek興味深いことに、質問は数字の等価性を文字列であるかのように比較することでした。事前に特定のパターンに制約された変数の場合に適合しますか?
エマニュエル14

あなたの例(b=234)はそのパターンに適合します-自分で割り当てたので+234でも "234"でも "233 + 1"でもないことを知っています。しかし、OPのスクリプトに、それは、コマンドライン引数として入力がかかるため、その制約を持っていない-として、それを呼び出すことを検討./param.sh 0+1./param.sh " 1"
godlygeek
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.