Geecul

Geekに踊ってカルチャーと寝る

test、[ コマンドは内部コマンド?、外部コマンド?

内部コマンド、外部コマンドどっちだっけ

はい、表題の通りです。

test コマンドは条件判定の際などによくお世話になるやつです。普段は if 文と一緒にお世話になることが多いのではないでしょうか。

test コマンドとは別件で詰まっていた時に、test コマンドについても調べる必要があり、

インターネットの海をさまよっていると以下の記事にたどり着いた。

不定期に「test は外部コマンド (/usr/bin/test) で [ は組込みコマンドだ」 などという話が涌きますが、 fumiyas.github.io

あれ、そうなんだっけ。

which コマンドで表示されるからどっちも外部コマンドだと思っていた。

user2@ubuntu2:~$ cat /etc/issue
Ubuntu 18.04.3 LTS \n \l

user2@ubuntu2:~$ echo $SHELL
/bin/bash
user2@ubuntu2:~$ which test
/usr/bin/test
user2@ubuntu2:~$ which [
/usr/bin/[
user2@ubuntu2:~$

which コマンドは、PATH 変数に記載されているディレクトリ先の実行可能コマンドのフルパスを表示する。

つまり、内部コマンドではなくて外部コマンドを表示するコマンドというわけだ。

ということで、test 、 [ コマンドは外部コマンドでした。


と言いたいが、そうは問屋が卸さない。

bash のマニュアルを test 、[ で検索すると以下の記述があることに気づく。

※ここでもマニュアルを確認できる。Man page of BASH

See the description of the test builtin command (section SHELL BUILTIN COMMANDS below) for the handling of parameters (i.e.  missing param‐
       eters).

ビルトインコマンド(=内部コマンド、組み込みコマンド)の説明を見てね、って書いてますね。

つまり、内部コマンド?と思ってマニュアルをさらに読み進めていくと・・・

 test expr
       [ expr ]
              Return  a status of 0 (true) or 1 (false) depending on the evaluation of the conditional expression expr.  Each operator and operand
              must be a separate argument.  Expressions are composed of the primaries described above under CONDITIONAL  EXPRESSIONS.   test  does
              not accept any options, nor does it accept and ignore an argument of -- as signifying the end of options.

あった!ということは内部コマンドにもある。

つまり、外部コマンドと内部コマンド両方用意されているというわけだ。


ということは、外部コマンドのほうを削除してもコマンドは使えるということですね。

本当に?

じゃあ、外部コマンドを削除して使ってみますか!

/usr/bin下のコマンドを削除して検証

まずは外部コマンドがあることを確認して

user2@ubuntu2:~$ which test
/usr/bin/test
user2@ubuntu2:~$ which [
/usr/bin/[

削除!

user2@ubuntu2:~$ sudo rm -i /usr/bin/test
rm: remove regular file '/usr/bin/test'? y
user2@ubuntu2:~$
user2@ubuntu2:~$ sudo rm -i /usr/bin/[
rm: remove regular file '/usr/bin/['? y
user2@ubuntu2:~$

で、削除できたことを確認。

user2@ubuntu2:~$ which test
user2@ubuntu2:~$
user2@ubuntu2:~$ which [
user2@ubuntu2:~$
user2@ubuntu2:~$ ls -l /usr/bin/test
ls: cannot access '/usr/bin/test': No such file or directory
user2@ubuntu2:~$
user2@ubuntu2:~$ ls -l /usr/bin/[
ls: cannot access '/usr/bin/[': No such file or directory
user2@ubuntu2:~$

それではこの状態でtestコマンドが使えるのか、確認していきしょう。

今回は、test の確認のために Hello1.bashを、[ の確認のために Hello2.bash を用意しました。

user2@ubuntu2:~$ ls -l
total 8
-rw-rw-r-- 1 user2 user2 84 Nov 17 06:29 Hello1.bash
-rw-rw-r-- 1 user2 user2 82 Nov 17 06:27 Hello2.bash
user2@ubuntu2:~$

まずは test から。以下を見てください。

user2@ubuntu2:~$ cat Hello1.bash
#!/bin/bash
if test Hello == $1
then
        echo "Hello World"
else
        echo "World End"
fi
user2@ubuntu2:~$

testコマンドが正しく使えていれば、

スクリプトの引数が Hello か、そうでないかで出力結果が変わるはずです。

user2@ubuntu2:~$ bash Hello1.bash Hello
Hello World
user2@ubuntu2:~$ bash Hello1.bash Hi
World End
user2@ubuntu2:~$

ちゃんと引数の違いで真偽を判定できていますね。

では次に [ もちゃんと使えるか見てみましょう。

検証用スクリプトの中身は以下です。

user2@ubuntu2:~$ cat Hello2.bash
#!/bin/bash
if [ Hello == $1 ]
then
        echo "Hello World"
else
        echo "World End"
fi
user2@ubuntu2:~$

では、スクリプトに引数を与えて実行します。

user2@ubuntu2:~$ bash Hello2.bash Hello
Hello World
user2@ubuntu2:~$ bash Hello2.bash Hi
World End
user2@ubuntu2:~$

うまく条件判定されました!

結論:内部コマンドも外部コマンドもある。

ということで、test 、 [ コマンドは内部コマンドも外部コマンドもあるよ!ということですね。

以下の記事にもありますが、主なコマンドは外部コマンドも内部コマンドも用意されているとのこと。

【※】主なビルトインコマンドは、同名でほぼ同じ機能の実行ファイルが「/bin」下に用意されているので、「which cd」ならば「/bin/cd」(CentOSでは「/usr/bin/cd」)のように表示されます。

www.atmarkit.co.jp

でもまあ、この記事を書くきっかけになった記事にもある通り、

シェルに組み込まないこともできるらしいんで、究極的には「環境による」ということなのかも。

少なくとも今回検証に使用した Ubuntu 18.04.3 LTS の bash には外部コマンドも内部コマンドも標準であるということで。

ほかの環境も似たようなもんだと思うんだけどね。

これ以上調べたらきりがないんで、今回はここまで! ちゃんちゃん!