読者です 読者をやめる 読者になる 読者になる

`[ "$a" == "$b" ]` ですって?!

tech shellscript shell

とある切っ掛けをもって,この際あらためて整理しておこうと思ってのメモ.

お話は shellscript .

思ったより長くなってしまったので...

tl;dr

  • [ "$a" == "$b" ] って言ってるの見た
    test コマンドなり [ では == はダメじゃなかったっけ? (今までの自分が幽体離脱)

  • 否,=== もどちらも正解
    "等しかったら" のオペレータとしてどちらも正しい,と言うのを知ったのですorz

  • ただしシェルによる
    これ POSIX 準拠の話.

  • POSIX を考慮するなら = を使っといた方が良いらしい
    == ではなく.

  • ここでは [ x = y ] で統一することに決めた
    [ x == y ] な書き方は当方ローカルルールとして違反とする.

でいいかな.

=? ==?

別件でたまたま踏み入れたページで目にした,こんな記載.;

[ "$a" == "$b" ]

震えが止まらなくなる.

ずっと [ x = y ] だと思って書いてきた.

なぜならそれが正解で,== はむしろ禁じ手とまで思っていたほど.

え?! これって間違い?

一気に,色々と気になり出す.

結果として分かったこと

まず...

両方ともに正解

どっち (で) もいい.

test コマンドにて "同じだったら" を評価する際の演算子として, = 使うも == を使うも,どちらもアリ,ということらしい.

string1 == string2
string1 = string2
    文字列が同じならば真となります.POSIX に準拠する形で test コマンドを使う場合には = を使う必要があります.

GNU Core Utilities (Coreutils) のドキュメントがあって,こちらではより明確に "同じ" と記載されています.;

‘string1 = string2’
    両文字列が等しければ,真.
‘string1 == string2’
    両文字列が等しければ,真 (= と同じ意味).

冒頭の「== は禁じ手とまで思っていた」と言う,その思い込みこそが間違い.

じゃぁ.

この擦り込みは一体何処から...というのが気になるところ.

で,思い起こしてみると,ここかと.

シェル,zsh 使ってるから

随分と前に,《test コマンドの文字列比較演算子の "等価" は == ではなく =》と言ったことを書いたことがありまして.

そこでは = not found なるエラーに遭遇.

そしてその原因は [ x == y ] なる書き方をしたが故のものだった,と言うものでした.

思えばその "擦り込み" は,この出来事がキッカケだった,と.

この時の苛立ちを発端にスボラな性分も助け,何の根拠を求めることなく極端に,== を "禁じ手" と自己洗脳することで,自分の中で整合をはかった,と.

ここで見えてきたことは,test コマンドおよび [ の条件式にて,x == y と言う書き方はシェルによって*1受け付けてくれないようですよ,と言うことかと.

丁度良いレポートが目に留まったので引用させていただきますと.;

まずはbashで以下を実行.
    $ [ a = b ] && echo true || echo false
    alse
    $ [ a == a ] && echo true || echo false
    true
同じコマンドをdashで実行.
    $ [ a = b ] && echo true || echo false
    false
    $ [ a == a ] && echo true || echo false
    [: 4: a: unexpected operator
    false
zshでもdashと同様の結果になりました.

両方ともに正解,だけどシェルによって違ってくる

って言ってしまってよいのでしょうか?

ここまでの話ですと,
= そして ==,どっち用いるも正解,と言えるのは,シェルによる,となるのでしょう.

その "正解" は,
bash だから成り立つもので,
zsh では成り立たない,となるのでしょう.

先に "どちらも正解 (同じ)" の根拠として引用した引用先は,いずれも bash のものでした.
そして "== はだめ (違う)" と見られたのは,zsh 上での話.

じゃぁ,bashzsh の違いからの問題か,と言いますと,おそらく正しくはソコではなく...

両方ともに正解,だけど POSIX 準拠を考慮するか否かによって違ってくる*2

POSIX が云々,と言う切り口は,これまでの引用箇所からも度々チラついてましたが改めて.;

POSIX に準拠する形で test コマンドを使う場合には = を使う必要があります.

[ x == y ] だと怒られる時があるけど,[ x = y ] と書いてれば怒られることはない,らしい.

とはいえども,実際のところどうなんだ,と言うのを知りたかった.

世の中はこの === かの摘み分けをどう扱っているのだろう.

って...



GraphViz Example: shells.dot
GraphViz Example: shells.dot / kentbye



= なの?,== なの?

総じて多い考え方は,"test および [ 使うのならば,オペレータは = の方が良いかもよ,一応 POSIX 準拠の話あるし" といったところでしょうか.

= を使う,[ .. ] 使うならね

意識するか否かはおいておいても,POSIX のことあるから.

You should not use == with [ or test, though. == is not part of the POSIX specification, and will not work with all shells (dash, in particular, does not recognize it).

すべてのシェルでは使えませんからね,例えば dash とか.

Using == here is bad form, as only = is specified by POSIX.

厳格です.

2項演算子"=="はtestコマンドには元々存在せず,
bashなど一部のシェルの組み込みコマンドで独自拡張されているものなので,
POSIX準拠に厳しいシェルでは使えない事が多いです.
シェルスクリプトを書くという観点ではあまり勧めない方が良いかと思います.

一方, 表現は,元よりシェルの拡張ですし,
"="ではなく"=="の方が正式な表現と規定されている事が多いような気はしますが,
大抵はどちらでも使えるので,私が人に教えるときには混乱を避けるために"="を使うよう勧めています.

このように明快に言及頂いているのは,素人にとって大変助かります.
ちなみに,

== is a bash-ism. The POSIX form is =. If portability to non-bash shells is important, use =.

こう言うの "ポータビリティ portability" という単語で表現するの,初めて知りました.

ポータビリティーは意識していないのですが,=を使おうと思います.

とは言っても...

== を使う,bash とかなら

POSIX 準拠の問題がない環境下にあるなら == 使えば良いではないでしょうか.

It's also worth noting that == was introduced in bash, but bourne shell does not support it. ... The == being unsupported in bourne was the reason it failed on the one.

bash だったら良いんじゃないでしょうかね,== 使う,で.

== is a bash-specific alias for = and it performs a string (lexical) comparison instead of a numeric comparison. eq being a numeric comparison of course.

Finally, I usually prefer to use the form if [ "$a" == "$b" ]

bash で文字列の比較なら == で良いのではないでしょうか?
つかこの "===bash 特有のエイリアス bash-specific alias" って? エイリアス?

There's no difference, == is a synonym for = (for the C/C++ people, I assume).

しかも,C/C++ 使っている人たちにとっても == の方が馴染みあるでしょうし.

幅広いシェル環境で動作するシェルスクリプトを記述するためにはtestコマンドで「=」を用いるのがよいようだ.ただし,シェルスクリプト以外の言語で一致を示すのは「==」となることが多い.

他の多くの言語は == というのもあります.

If you really insist to use == then put it in between [[ and ]]. (And make sure that the first line of your script specifies to use /bin/bash.)

これは bash 前提に,== 使うんだったら [[ .. ]] 使えよ,って言ってますね.
=== を追っていると,どうしても [ .. ] および [[ .. ]] の次元の話も出てくるのですが,更にこれを掛け合わせるとなると,散らかしてしまいそうなので,[ および [[ はまた別の話として,ここでは触れないことにしたいと思ってます.

最後にちょっと違った切り口も目に付いたので加えておきたいと思います.

比較対象が文字列か数値か

ちょっと遠回りな話で,端的に言いますと == は数値の比較を行う (( .. )) の中で使うもの,と言う論調になるのかしら.

そしてこの考え方の背景にはおそらく,等号 "=" を使った [*3 による評価は,文字列としての評価である,と言うところが有るんだろうと思います.
文字列の比較/評価をするための道具は,[ および [[ で,そこでは = および == を使う.
数値の評価をしたいならば,使う道具は (( .. )) で,これでは == しか使えない.= は使えない.
とは言ってもやっぱり [ および [[ 使って数値の比較/評価をしたい場合は,= および == というオペレータではなく,-eq 等を使うことになる.

ちょっと持ってき方としてクドイかな.

You must use == in numeric comparisons in (( ... )):
:
You may use either for string comparisons in [[ ... ]] or [ ... ] or test:

:
    $ if [ 3 == 3 ]; then echo "yes"; fi
    yes
    $ if [ 3 = 3 ]; then echo "yes"; fi
    yes
:

== は数値の評価としてのオペレータで,複合コマンド (( ... )) による算術式評価の中で使うものですよ,と.

There's no difference for string comparisons, but you can't use = for numeric comparisons in (()) (you must use == in (()) or -eq in [], test or [[]].

文字列の比較/評価だったらどっちでも良いですけど,数値だったら (( .. )) で,その中では = は使えないよ,と.

ちなみに

以下,= とか == に関する,雑多なメモ.

[ x = y ] とか [ x == y ] という比較/評価は,文字列として

先ほど触れましたが.

While you can do 1 == 1 or [[ $*4 == 2 ]] it is testing the string equality -- not the arithmetic equality.

数値としてではなく,文字列として評価している,と.

ちなみに == は,= の "拡張" なのだそう

とか,他にもこんな感じで.;

bash-4.3.30/test.c にも bash-4.3.30/doc/bash.info にも
== は =と同様文字列の等値比較であると書かれています.
POSIX 適合性を取るなら = を使え,とありますね.
==bash拡張機能でしょう.

via. [bash - testコマンドの文字列比較条件式で'=='は許容されているのか? - スタック・オーバーフロー][42]

とか.

先にも引用した箇所ですが,ここでも改めて再度引用させていただきますと.;

2項演算子"=="はtestコマンドには元々存在せず,
bashなど一部のシェルの組み込みコマンドで独自拡張されているものなので,

via. [bash_zshにおける「[」(test)コマンドと複合コマンド「[[」との違いについて - 試験運用中なLinux備忘録][43]

結果として決めたこと 「= だけ」

どっちでも良いんだったら,そう神経質にならず,どっち使うでも良いのでは,となるのでしょうが.

言えども,たった 2 択.

たった 2 択のために,今回のような混乱を繰り返すのもいかがなものか,と感じるのと,そして何よりこの少なすぎる自身の記憶領域のためにも,どちらか一方に完全に寄せて納めておくのが精神的衛生のためにも良いのでは,と考え...

決めたわけです.

全部 [ x = y ] って書こ

[ x == y ] じゃない.

今回の作業,ここまでで分かったことを元に,現時点,それは "個人的に" なローカルで全然構わないと考えてます.

その拠り所として,ここでは.

ログインシェルに zsh 使うし

という所に求めるで良しとしてます.

本来ならば,"シェルは zsh なので" より,これまでも触れて来たよう "POSIX 準拠を云々" とするべきなのでしょうが,そこまで言ってしまうのはどうも今の自分にとって大げさと言うか,身の丈に合っていないような気がしてならないので,とりあえず避けることにしてます(笑

その他にも

[ x == y ][ x = y ] か,あるいは [ x == y ] によるエラーがそんなに気になるのならば...

ひとつはそもそも zsh の選択自体が問題だろ,と言う切り口.
ましてや macos がデフォとして提供しているのは bash.黙って使っていれば [ x == y ][ x = y ] かなんて悩む事自体無かった.にも拘らず zsh.その選択自体から見直すべきじゃ?,ってな感じ.

確かに(笑.ぐうの音もでません.

ま,これについては,逆にそうであるがゆえにログインシェルを bash にする程でもないかな,という,実に程度の低い発想しかありません.

ましてや今回の話は,=== かをハッキリさせる,という話で,シェル何使うか,と言う部分にまで及ぶつもりも,そんなこと期待もしてないし,それ以上は別の話として散らかりそうなので,あまり深く考えていなかったり,というのが正直なところ.

そしてふたつめとして考えられるのが,そんなに気になるのだったら [[ 使えば良いだろ,って話.[ ではなく.

どうも,[[ 使えば,そう言った事気にすることないよ,と言った趣の話もチラホラあるようで.

しかも [[ の方が機能的にも,見た目的にも殆んどの点で優れているらしい.

そしてこれに関しても先のシェルの話同様でして,[ x = y ][ x == y ] かキッカケに,[[ を使う事に,そう大きな必然性? 必要性? なりを感じられない,と言うのがあったりします.

更には,これはちょっと情緒的かもしれませんが,[ x == y ] に依るエラーの対処療法的なアプローチで [[ を,というのも個人的にあまり気持ちが良い感じがしないのもあって.



ということでして...

それにしても,=== は同じ,だけど...なんて,こんな小面倒臭い混乱するようなことにしたのだろう,と正直思ったり...単なる逆切れですが.

あとあれですかね,これ繋がりで次に [ および [[ を並べての整理をしておいた方が良いかな.
つか "整理" になるかどうか自体,心配ですが.

つこって,はいおしまい.

*1:自分の場合は "zsh なので" となるでしょう.

*2:POSIX 仕様のシェル,とか POSIX 準拠のシェルとか,って言ってよいのかな.この辺りが自信無かったので.

*3:勿論 ’[[’ も.

*4: 1+1