似てて紛らわしいものシリーズ [[ / [ / test
bash の記号で初心者泣かせの、似てて紛らわしかったり、使い分けがわからなかったり、読み方を間違えてパニックになる記号について書く
[ / [[ の違い
結論から言います [[ / [
は同じものです。 [[
が新しい書き方で機能強化されています。
[ / test の違い
違いはありません。同じものです。*1
[[ は [ とほぼ同じ機能と目的を持ちます。
個人的な意見ですが、 bashを書く上においては [[
でいいと思います。
というか bash が動かない環境なんてもうなくなったんだし、 [[
でいいと思います。個人的な意見ですが。
[/ [[ のヘルプを見てみます。
ちなみに bash で「返す」といえば終了ステータスのことです。
help [[
[[ ... ]]: [[ expression ]] 条件式のコマンドを実行します。 条件式 EXPRESSION の評価結果に基づいて 0 または 1 を返します。 (略 終了ステータス: EXPRESSION の値に基づいて 0 または 1 を返します。
help [
[: [ arg... ] 条件式を評価します。
[
は POSIXの古い書き方*2。UNIXの考古学をする人なんかが好きそうです。
機能面でも違う
おさらいです。
[
は古い[[
は出来ることが増えた
bash を使う限りにおいて 積極的に [[
を使って構いません。っていうか [[
つかえ*3
[
は古いが役に立つ。
[
は後方互換性(つまり古いシェルスクリプトや sh だけに書かれたもの)を実行するときに今でも使われるようです。
dash / sh
などのインタプリタや、POSIX互換原理主義に染まってる方々は使うことが多いようです。
なんで [[ なんてものが導入されたのか
TODO:このへんもう少し詳細に書くべき、いつから、なんのために、どうして、どこで使えるのか
便利だから。
[[ は [ に比べてどの辺が便利?
[[ は && が使える [[ は || が使える [[ は -e FILEが使える [[ は -eq が使える [[ は = でglob マッチが使える [[ は =~ の 正規表現マッチが使える [[ は < で文字列長さ比較ができる
[[
は [
で出来ることは全てできるのです。*4
[
には出来なかった事が[[
にはできるのです。
なぜ [ では &&
が出来ないのか?
bash のコマンド記号に解釈されてしまうから。
たとえば、<記号は リダイレクトとかぶります。
command < finename
たとえば && 記号は コマンドの並列実行とかぶります
command && command
たとえば || 記号は パイプライン処理やコマンドの並列記述とかぶります
command || command
たとえば & 記号は バックグラウンド起動とかぶります
command &
これらはすべて、比較処理で衝突を引き起こします。
[ varname < varname ] # STDINリダイレクトに見える [ varname > varname ] # STDOUTリダイレクト に見える [ command || command ] # パイプに見える [ command & command ] # バックグラウンドに見える
[ を使うとエスケープ処理が必須!?
&&
や <
や >
、 |
といった記号がシェル・コマンドでで使われます。
そのため、[ を使うとエスケープ処理が必要になっていました。
## リダイレクトに解釈させない [ varname \< varname ] [ varname \> varname ]
エスケープ処理がとってもイメージしにくいですね!!!!
この<めんどくさい>エスケープ処理から私達を開放してくれる。
エスケープの解放軍は我らが [[
なのです。
エスケープ処理の有無による違いの例
$ [ aaaaa \< aaa ]; echo $? $ [[ aaaaa < aaa ]]; echo $?
どちらのほうが読みやすいですか。少なくとも初心者には後者だと思います。
ね? [[
でいいでしょ?
存在を認知して使い分けできたら、 test/[
なんて捨てちゃえよ。POSIX互換なシェルスクリプトを書くときだけ[[
を [
に書き換えたらいいでしょ *5
[ / test
の更に困ったこと。
[
には2種類あります。
一つが bash のビルトイン関数 [
。もう一つが /usr/bin/[
です。
[
はそのファイル名のコマンドでもあります。
2種類の [
、1つだけの [[
つまり、 [
は二種類あります。次の2つです。
- function [
- /usr/bin/[
それに対し [[
は関数のみです
- builtin function
[[
関数とコマンドどちらが優先されるのでしょうか?
優先度は ビルトイン>ファイル
関数 PATH
そのため通常はビルトイン関数が優先度が高いので ビルトイン関数が使われます。
GNU Bashをメインで使う私達にとって、/usr/bin/[
は互換性のためにあると行っても過言ではないと思います。
[
と test
はほぼ同じものです
[ / test
は次のすべてが候補になります。
- ビルトイン関数 [
- /usr/bin/[
- /usr/bin/test
- ビルトイン関数 test
4つもある・・・互換性のために test / [
がいくつもあって更に混乱を招くことになっているのです。
わけわからんわ。 わたしは [[
でいく!みなさんもどうですか?
わたしは、test は help test
で比較条件を見るときだけ使うことにしました。
騙されたと思って [[
だけで書くといいですよ。
[[
を使うときの 一つだけ注意
[[
を使うときは test -a / test -o
は使わないこと。これでスッキリしますよ
takuya@~$ [[ 0 = 0 && 1 == 1 ]] ; echo $? 0 takuya@~$ [[ 0 = 0 -a 1 == 1 ]] ; echo $? -bash: 条件式に構文エラーがあります -bash: `-a' 周辺に構文エラーがあります takuya@~$