似てて紛らわしいものシリーズ =/==と=
bash の記号で初心者泣かせの、似てて紛らわしかったり、使い分けがわからなかったり、読み方を間違えてパニックになる記号について書く
=/==と= の違い
=
はいくつかのパターンで出てきます。
これらのそれぞれで微妙な差異があるのです。めんどくさいよねー
大きな違い。両端スペース
=のスペースの関係。他のプログラミング言語を触った人はこのへんで、頭が???になると思う。
変数に代入するときはvarname=value
のように書く、スペースは許されない。
文字列を比較するときは [[ / [
の中で使われる。スペースの有無は問われない。
変数に代入する場合(文字列)
vaname=value
スペースは許されない
vaname = value # コマンド引数に見えてしまう。
比較で使う場合(文字列
# どちらも可 [[ $vaname = value ]] ; echo $? [[ $vaname=value ]] ; echo $?
数値を扱う場合。
数値を扱う場合、文字列の場合と違って=
は 代入、 ==
は比較と明確に区別されます。
ただし、 let
と (( ))
で記述が異なります。
こちらも=のスペースの関係が異なるので、頭の中をスッキリさせないと混乱します。
変数に代入する場合
let i=0 (( i=0 )) (( i = 0 ))
let でスペースは許されない(重要
# 次の記述は出来ない let i = 0 let i= 0 let i =0
(( ))
ではスペースは許される
### 次の記述はすべて許される。 (( i = 0 )) (( i= 0 )) (( i =0 ))
比較演算子としての=
文字列の比較演算子として使うとき = / ==
のどちらも同じ役目を果たす。
さらに、= / ==
の右辺値はglob のパターンとして扱われる。$
から始まる文字列($nameなど)は比較前に変数が展開される。
さらに、glob は shopt extglob
で拡張パターンを使うことが出来る。
拡張パターンは正規表現っぽくて反って分かり辛いので、正規表現比較 =~
を使ったほうがわかりやすい。
=/== の比較の例
[[ $name = takuya ]] ; echo $? # == と同じ [[ $name == takuya ]] ; echo $? # = と同じ [[ $name == $username ]]; echo $? # 両方に変数が使える。 [[ $name == taku* ]] ; echo $? # 右辺値は常にglobと解釈されるです。 [[ a = [a-z] ]] ; echo $? # 正規表現ではなくglob です [[ a =~ [a-z] ]] ; echo $? # これは正規表現
とくに extglob on でのみ許される [[ = [a-z] ]]
はshopt 環境に左右されるので怖いね
まとめ
ややこしいよね。とくに =前後のスペースはハマりどころだわ。
出現箇所/opr | REPL | [[ / [ | (( / $(( | let |
---|---|---|---|---|
a=0 | 代入 | 比較 | 代入 | 代入 |
a = 0 | cmd:a args:= 0に解釈 | 比較 | 代入 | syntax error |
a==0 | a='=0' | 比較 | 比較 | 比較 |
$a=$name | 変数展開+代入 | 変数展開+比較 | 変数展開+代入 | 変数展開+代入 |
a=str | 代入 | 比較 | 変数展開+代入 | 変数展開+代入 |
注意点
この記事においては、コマンドの PS1があると非常に見づらいので、PS1=''
にした
$ (( 1==1 )) #$(( 1==1 )) に見えてしまう。 (( 1==1 )) #こうした
$ varname=string #$varname=string に見えてしまう。 varname=string #こうした
参考資料
- bash -x による実行により確認した。