[Bash] testと[と[[

bashには色々とif文の書き方があるようです。
知らなかったので、まとめてみたいと思います。

### 事の発端
- - -
この調査を始めるきっかけは、[Google Shell Style Guide](https://google.github.io/styleguide/shell.xml)と呼ばれる資料に目を通してからです。
これは「Googleは社内でBashをこう書いてるよ！！」と示したコーディング規約です。
他にも多種多様な言語に対するスタイル集もあります。
[C++](https://google.github.io/styleguide/cppguide.html)とか[Python](https://google.github.io/styleguide/pyguide.html)とかもあったりします。
※日本語訳して下さっている私に比べて遥かに優秀な方がいらっしゃいました。
[C++](http://www.textdrop.net/google-styleguide-ja/cppguide.xml)
[Python](http://works.surgo.jp/translation/pyguide.html)

私は綺麗であれば何でもいいと思うので、このGoogle Style Guideに則って書くことが多いです。
※いちいち考えて、その挙句に周りからチクチクされるの面倒ですし、
なにより「Googleがやってますよ！」って言えばなんか説得力ありますよね（無いよ）

### Google Shell Style Guide
- - -
このGoogle Shell Style Guideには、[このような記述](https://google.github.io/styleguide/shell.xml#Test,_[_and_[[)があります。
※以下、超テキトーな和訳なので、ご自身で和訳してください。

>test と [ それから [[
>[[ ... ]] の書式は、testコマンドや/usr/bin/[よりも推奨される。
>[[...]]はエラーを減らすことができる。
>[[と]]との間でパス名展開や単語分割が行われないし、[[...]]の書式は正規表現を許容するからね

>>**akinomyogaさんのコメントより追記**
>>単語分割については、akinomyogaさんがコメントに補足コードを載せてくださいました。
>>akinomyogaさんの補足は必見ですよ！（他人任せ）
>>
>>**tadsanさんから頂いたコメントのサイトを見て追記**
>>Googleの記述はregular expressionとなっていたので、**正規表現**と訳しましたが、
>>>パターンの表記はglobという類のもので、正規表現ではない。
>
>>とありますので、正しくは**globライブラリを許容する**という意味合いと思われます。


### testはコマンド
- - -
……うん、そうだろうね。
これはbashの記事だけど、fishさんはtestコマンドが推奨されていますね。
気を付けたいものです。

>**akinomyogaさんのコメントより**
>typeコマンドを使えば、**ビルトインコマンドも存在する**ことが分かる旨のご指摘をいただきました。


### [もコマンド
- - -
マジですか。知らなかった
なんか、``/usr/bin/[``ってシュール……(´･_･`)

```bash
$ which [
/usr/bin/[
```
>**akinomyogaさんのコメントより**
>typeコマンドを使えば、**ビルトインコマンドも存在する**ことが分かる旨のご指摘をいただきました。


こいつは特殊な比較演算子を要求します。
`-lt`とか`-gt`とか`-eq`とかなんやねんって感じですね。

``` bash
readonly sample=1
if [ ${sample} -lt 2 ]; then
  echo '変数「sample」は2よりも小さい！'
else
  echo '変数「sample」は2以上！'
fi
```
- `-lt` -> lesser than
- `-gt` -> greater than
- `-eq` -> equal

でも仕方ないですよね。
<font color="Red">**-gtとかは[コマンドのコマンドオプションなんだもん！**</font>
`ls -l`の`-l`と同じだよ！

### [[はコマンドじゃない！
- - -
``` bash
$ which [[
$ #何も出力されない
```
~~`[[`はbuilt-in commandと呼ばれるものらしいです。~~
`[[...]]`の<font color="Red">**閉じるまで含めて**が複合コマンド</font>と呼ばれるものです。

bashそのものに含まれている構文みたいなやつ。

```bash
readonly sample=1
if [[ ${sample} < 2 ]]; then
  echo 'sampleは2より小さい！'
else
  echo 'sampleは2以上！'
fi
```
まるで高級言語を扱っているようだ……

>**akinomyogaさんのコメントより**
>算術式を用いない場合に正しく演算されないパターンがあることをご指摘いただきました。
>ご参照下さい。（お前、もっとなんか書け）
>ちゃんとテストしてれば分かったこと……いや、**辞書式比較**という真相まではたどり着けなかったでしょうね……


### どれがいいの？
- - -
bashがあっても、`test`や`[`のコマンドが無ければそのシェルスクリプトは使えない。
ところがぎっちょん`[[`に関しては、bashに組み込まれているからbash環境ならどこでも使える。
どっちがいいかは分かるね？
という感じなのがGoogleの見解らしい。

**tadsanさんから頂いたコメントの下記サイトを見て追記**
>幅広いシェル環境で動作するシェルスクリプトを記述するためにはtestコマンドで「=」を用いるのがよい

`[[...]]`がbash「のみ」が解釈できる複合コマンドである場合、

- bashが存在すれば必ず解釈される・できる（メリット）
- 他のシェルでは必ずしも解釈されるとは限らない（デメリット）

他のシェルを含めてサポートしたい場合は、bash特有の記法は問題になります。

また、Googleの立ち位置は、Shell Style Guideにはこう書いてあります。
>Bash is the only shell scripting language permitted for executables. 
>Restricting all executable shell scripts to bash gives us a consistent shell language that's installed on all our machines. 
>【テキトー訳】
>Bashは（Google社内で）~~実行できる~~<font color="Red">実行ファイル</font>として許可されている唯一のシェルスクリプトである。
>実行できるシェルスクリプトをBashのみに制限することで、私たちはすべてのマシンで一貫したシェル言語を得られる。

Googleは社内で使用できるシェルスクリプトについてBash以外を認めていないようです。

**社内のスクリプト言語をBashに限定する代わりに、統一した思想、コーディングができる。**
**だから、このスタイルガイドはBashのみに焦点を当てたモノになっているし、**
**Bash以外はサポートしなくていいから、色んなメリット（※1）のある複合コマンドの方を使おうね**
**※1：パス名展開や単語分割、正規表現（globライブラリ）を使用できること**

ということなのだと思います。
あまり英語が得意ではないので、誤訳があればご指摘ください。
**miyuさんから頂いたコメントでより正確な内容が分かります。そちらも参照してください。**


### 最後に、それホント？
- - -
Googleの言うことは論理的正しいというか、まぁ間違ってないと思います。
個人的にはC++などの言語と同じ比較演算子が使えるのは精神衛生上よろしかったです。
※全部が全部使えるわけではなさそうだけど(´･_･`)

でも、testや[がないようなbashってあるんでしょうかね？
自宅のubuntu16.04さんのbashrcを見てみました。

```bash:.bashrc
（前略）
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi
（以下略）
```

**デフォルトがめちゃくちゃ if [ xxx ] 使っとるやんけ！！**

>**akinomyogaさんのコメントより**
>testや[には通常コマンドのほかに、ビルトインコマンドが存在することをご指摘いただきました。
>そのため、`test`や`[`の**通常コマンド**がなかったとしても使えます。