nikkie-ftnextの日記

イベントレポートや読書メモを発信

読書ログ | bashのtestと[と[[(『マスタリングLinuxシェルスクリプト 第2版』)

はじめに

アタイも挑戦したい、管理人みたいに1、nikkieです。

シェルスクリプトを書いたり読んだりする中でif文の条件に使う[が1つだったり2つだったり、違いがよく分からないなと感じていました。
『マスタリングLinuxシェルスクリプト 第2版』にあたって深まった理解を、[が分からない過去の私向けにアウトプットします。

目次

まとめ:現時点のtest[[[の理解

シェルスクリプトに関しては伸びしろ豊富と思いますので、フィードバック大歓迎です。

  • test[は同じ(違いはない)
    • [test省略表記
  • [[test[より高機能

動作環境

macOS 12.6のPC(zshがデフォルト)で、bashを立ち上げて動作確認しました。

% bash
$

test[[[

test

シェルの組み込みコマンドです。

$ type test
test is a shell builtin
$ which test
/bin/test

test -eはファイルが存在するかをテストします。

  • 存在していたら終了コードは0
  • 存在していなければ終了コードは1
$ touch awesome.txt
$ test -e awesome.txt ; echo $?
0
$ rm awesome.txt
$ test -e awesome.txt ; echo $?
1

オンラインで読めるマニュアルはこちら2

[

シェルの組み込みコマンドです。
(ちょ、おま、コマンドだったの!?)

$ type [
[ is a shell builtin
$ which [
/bin/[

[testコマンドの省略版です。
man testより

test, [ – condition evaluation utility

test[は同じ!
先ほどの例を書き換えてみましょう。

$ touch awesome.txt
$ [ -e awesome.txt ] ; echo $?
0
$ rm awesome.txt
$ [ -e awesome.txt ] ; echo $?
1

[[

キーワードです。
キーワードには他にifなどがあります。

$ type [[
[[ is a shell keyword
$ type if
if is a shell keyword

test[の例は[[を使っても書き換えられました。

$ touch awesome.txt
$ [[ -e awesome.txt ]] ; echo $?
0
$ rm awesome.txt
$ [[ -e awesome.txt ]] ; echo $?
1

test[との違いは「高度な条件テスト」ができることだそうです(『マスタリングLinuxシェルスクリプト 第2版』 5.4)。
この記事では立ち入りませんが、パターンマッチングや正規表現を使った条件テストが紹介されていました。

例で見るtest[[[

ここまでに確認した例をスクリプトにまとめました3
testの例も[の例も[[の例も、書き方は異なりますが動作としては同じです。

$ touch awesome.txt
$ ./test_and_brackets_single.sh
awesome.txtあり
awesome.txtあり
awesome.txtあり
$ rm awesome.txt
$ ./test_and_brackets_single.sh
awesome.txtなし
awesome.txtなし
awesome.txtなし

もう一例:複数の条件の場合

if文の条件が複数ある場合、test[と、[[の間で違いがありました

test[は2つの書き方ができます:

  • testコマンドにコマンドラインリストが使える(=&&||でつなげる)
  • testコマンドの複数のオプションを(-a-oで)つなげる4

[[は複数のオプションを&&||つなぐのみです。
-aでつないでみたら「syntax error in conditional expression」と表示され、できないってことかなと認識しました5

複数の条件のスクリプト例はこちらです:

$ touch awesome.txt
$ ./other_example.sh
awesome.txtがあって読める
awesome.txtがあって読める
awesome.txtがあって読める
$ rm awesome.txt
$ ./other_example.sh
awesome.txtがないか読めない
awesome.txtがないか読めない
awesome.txtがないか読めない

IMO:test[[[の使い分け

test[が同じ意味と理解しました。
この2つであれば打鍵数が少ない[を使いたいかなという気持ちです。
[はコマンドと知られたのが大きいなと感じています。

[[ですが、test[と同じことができ、[[にしかできないこと(パターンマッチや正規表現)もあるという理解です。
[[[は複数の条件のつなぎ方が異なるので、[[がどうしても必要でない限りは[を使いたいなと思いました。
[[[を併用すると、慣れていないがゆえに混乱しそうなのですが、[に統一することでそれを避けられそうと考えています。

終わりに

test[[[、完全に理解した!
同じ部分・違う部分が分かったことで、使い分けの指針(暫定版)もできました。
シェルスクリプトif文を書くときに[の数に迷わずに書いていけそうです!

参考文献

1章

  • 1.3 bashスクリプトとは何か?
    • ;でコマンドをつなぐ書き方(testコマンドの返り値の確認で使用)
  • 1.4.1 コマンドの種類
    • typeコマンドを使った、コマンドの種類の確認

3章

  • 3.1 コマンドラインリストを使ったシンプルな決定経路
  • 3.3 シェル組み込みコマンドのtestの使用
  • 3.6 testコマンドを伴うif文

5章

  • 5.1 testコマンドの要約
  • 5.4 [[を使った高度なテスト


  1. https://youtu.be/P5LLhoKfI1E?t=36
  2. この文書はもうメンテナンスされていない」とありますが、Man page of TESTは、オプションを日本語でざっと知る助けになりました
  3. if文の条件の評価はセミコロンを入れて1行にする書き方とセミコロンは入れずに改行してthenを続く行にする書き方があることを知り(ref: 3.4)、このスクリプトで試しています
  4. ShellCheckによると、複数のtestコマンドをコマンドラインリストでつなぐ方が好ましいようです。ref: ShellCheck: SC2166 – Prefer `[ p ] && [ q ]` as `[ p -a q ]` is not well defined.
  5. ShellCheckによると[[の中では-aの代わりに(instead of&&を使うべきなようです。ref: ShellCheck: SC2108 – In `[[..]]`, use `&&` instead of `-a`.