[ command returns exit-status zero if expression, contained in its arguments, is considered true and non-zero exit-status if expression, contained in its arguments, is considered false. It also fails with error message if its last argument isn't
] (this is done purely for aesthetic reasons).
[ hello ]
echo "Exit-status of [ hello ] is:" $?
[ abc = abc ]
echo "Exit-status of [ abc = abc ] is:" $?
echo "Exit-status of [ ] is:" $?
[ abc = def ]
echo "Exit-status of [ abc = def ] is:" $?
… will output:
Exit-status of [ hello ] is: 0 — because non-empty string is considered true
Exit-status of [ abc = abc ] is: 0 — because 'abc' really is same as 'abc'
Exit-status of [ ] is: 1 — because empty string is considered false
Exit-status of [ abc = def ] is: 1 — because 'abc' really differs from 'def'
However, bash and many other shells really usually don't invoke
/usr/bin/[) in these cases, but call built-in command with exactly the same behavior instead (purely for performance reasons). To invoke
/bin/[ (not shell built-in surrogate) you need either to explicitly specify its path (e.g.
/bin/[ hello ]; you don't need to prefix
] with dirname though ☺), or to configure shell not to use a built-in surrogate (for example,
enable -n [ in bash).
P. S.: As it was said in other answers,
[ is related to
[, doesn't require
] as its last argument (and doesn't expect it at all; adding extra
test arguments can cause it to fail with error message or to return wrong result). The
/bin/[ can resolve to the same file (e.g. one is symlinked; in this case the behavior diversion is probably implemented by analyzing the currently-called command within the
[ code itself) or to different files. For
test, shell also usually invokes built-in surrogate, unless path is explicitly specified (
/bin/test) or it's configured not to do so (
enable -n test).
P. P. S.: Unlike
if is never a real file. It's part of shell (e.g. bash) syntax:
if commandA; then commandB; fi (newlines can be used instead of semicolons) causes
commandB to be executed if-and-only-if
commandA exited with zero status. This perfectly fits to behavior of
[, allowing to combine them like
if [ "$a" = foo ]; then …; fi (or
if test "$a" = foo; then …; fi — just less readable). However, modern scripts often use
[[ instead of
[, which (as the
if) is never a real file, but always a part of shell syntax.
P. P. P. S.: As for
man — never expect
man to have an article on every command in your file-system. Info on some (even "real", file-based) commands may be missing, info on some shell built-ins maybe present not only within an article dedicated to specific shell (that's the place where you most certainly will find info on
[[). Still, many distributions have explicit
--help, it's not recognized with
test for obvious reason: it needs to handle quietly cases like
a=--help; test "$a"; on some distributions
[ --help (without closing
]) still shows help, on some it doesn't.)