test と [

昨日のエントリに関して。

きむら 『test ([)内部で、自分が ’[’ という名前で呼ばれたら引数で渡された ’]’ を
特別扱い(というのか?)してるんですよね。』 (2006/12/31 01:11)

そうそう、確かそうだったはず、と思うものの、念のために GNU coreutils 5.93 のコードを確認。あれ、[ は test の hard link じゃない。
test は test.c から、[ は lbracket.c からコンパイルされるようになっているんだけど、test.c の中身を抜粋するとこんな感じ。

#ifndef LBRACKET
# define LBRACKET 0
#endif

/* The official name of this program (e.g., no `g' prefix).  */
#if LBRACKET
# define PROGRAM_NAME "["
#else
# define PROGRAM_NAME "test"
#endif
  if (LBRACKET)
    {
      /* Recognize --help or --version, but only when invoked in the
         "[" form, and when the last argument is not "]".  POSIX
         allows "[ --help" and "[ --version" to have the usual GNU
         behavior, but it requires "test --help" and "test --version"
         to exit silently with status 1.  */
      if (margc < 2 || !STREQ (margv[margc - 1], "]"))
        {
          parse_long_options (margc, margv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
                              usage, AUTHORS, (char const *) NULL);
          test_syntax_error (_("missing `]'\n"), NULL);
        }

      --margc;
    }

で、lbracket.c は2行。

#define LBRACKET 1
#include "test.c"

[ で呼ばれたときは ] を特別扱いしているのには違いないんだけど、argv[0] を見て動的に挙動を切り替えるんじゃなくて、コンパイル時に挙動が決まっているというオチ。
まぁ、これも GNU coreutils を採用している OS での話で、FreeBSD なんかは昨日書いたように test と [ は hard link で argv[0] を見て動的に挙動を切り替えているというので正しい。
あと、コメントにも書いたけど、bash/zsh では test は builtin だから実際にこれらのプロセスが生成される機会は結構少ない。Linux だと大抵の場合 /bin/sh は /bin/bash への symbolic link だし。