I noticed while answering another question that test and [ are different binaries, but the [ manpage pulls up test's. Besides the requirement for an ending ], is there any difference? If not, why are they separate binaries instead of being symlinked? (They are also bash builtins, and bash doesn't show a difference either.)


The source code explains the difference as being how it handles the --help option.

  /* Recognize --help or --version, but only when invoked in the
     "[" form, when the last argument is not "]".  Use direct
     parsing, rather than parse_long_options, to avoid accepting
     abbreviations.  POSIX allows "[ --help" and "[ --version" to
     have the usual GNU behavior, but it requires "test --help"
     and "test --version" to exit silently with status 0.  */


$ /usr/bin/test --help
$ /usr/bin/[ --help
Usage: test EXPRESSION
  or:  test
  or:  [ EXPRESSION ]
  or:  [ ]
  or:  [ OPTION
Exit with the status determined by EXPRESSION.

In the bash builtin version, the only difference is that [ requires ] at the end, as you said.

| improve this answer | |
  • 1
    Interesting, though most programs achieve the same behavior with a symlink. – Kevin May 6 '12 at 16:33
  • 2
    They're hardlinks to the same inode on my system. The benefit of this over symlinks is that if the symlink target gets removed or moved, the symlink no longer works. If one of the hardlinks to an inode gets moved or removed, all the hardlinks continue to work. – nobody Jun 20 '14 at 15:56

Normally, they are the same binary with hard links. Depending on the shell, an internal implementation may be used for test and [ tests rather than the binary. This is more efficient in terms of process spawning, and may provide different options than the binary program test provides.

Other than the the differences in call format, they both provide the same functionality.

| improve this answer | |
  • 8
    Amazingly enough, in Debian's coreutils they aren't the same binary. The same source is compiled two times, one defining PROGRAM_NAME as "test", and other defining it as "[" and with some additional code to test that the expression ends with "]". o_O – angus Jan 9 '12 at 17:58
  • 3
    @angus Another example of this is ls/dir/vdir. Coreutils seems to like building different hardcoded binaries rather than testing argv[0] at runtime. – Random832 Jan 9 '12 at 18:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.