How exactly does "/bin/[" work?

The [ command's job is to evaluate test expressions. It returns with a 0 exit status (that means true) when the expression resolves to true and something else (which means false) otherwise.

It's not that it does nothing, it's just that its outcome is to be found in its exit status. In a shell, you can find out about the exit status of the last command in $? for Bourne-like shells or $status in most other shells (fish/rc/es/csh/tcsh...).

$ [ a = a ]
$ echo "$?"
0
$ [ a = b ]
$ echo "$?"
1

In other languages like perl, the exit status is returned for instance in the return value of system():

$ perl -le 'print system("[", "a", "=", "a", "]")'
0

Note that all modern Bourne-like shells (and fish) have a built-in [ command. The one in /bin would typically only be executed when you use another shell or when you do things like env [ foo = bar ] or find . -exec [ -f {} ] \; -print or that perl command above...

The [ command is also known by the test name. When called as test, it doesn't require a closing ] argument.

While your system may not have a man page for [, it probably has one for test. But again, note that it would document the /bin/[ or /bin/test implementation. To know about the [ builtin in your shell, you should read the documentation for your shell instead.

For more information about the history of that utility and the difference with the [[...]] ksh test expression, you may want to have a look at this other Q&A here.


I am always surprised that in the folder /bin there is a [ program.

You are right to be surprised. That's one of the rare POSIX commands, with the null utility (:), that doesn't respect the commands file allowed characters convention (portable filename character set).

Is is what is called when we are doing something like: if [ something ]?

Precisely but it can be used without the if too.

By calling the [ program explicitly in a shell it asks for a corresponding ], and when I provide the closing bracket it seems to do nothing no matter what I insert between the brackets.

It does nothing visible but it actually does the very same thing than when used with if, i.e. it sets the exit status to 0 (true) or anything else (false) depending on what you put inside the brackets. It is (for a reason) the same behavior as the test command; the only difference is that it looks for the ending ]. See man test for details.

Needless to say, the usual way about getting help about a program does not work, i.e. neither man [ nor [ --help works.

That depends on your Operating System. man [ definitely works for me on a couple of mainstream Gnu/Linux distributions but it doesn't on Solaris.

[ --help might work or not depending on the implementation as it is breaking the syntax anyway, missing the ending ]. Moreover, the POSIX standard for the test / [ command explicitly rules out all options, including the -- option termination so both [ --help ] and test --help need to return true and be silent by design. Note that what you put inside the brackets or after [ and that look like options (e.g. -f file, -n string, and the likes) are not options but operands.

All modern Bourne style shell interpreters (like bash, ksh, dash and zsh to name a few) implement the test/[ utility internally as a builtin so when you use them, the right manual page to refer to might be the one of the shell, not the test one.

Before Unix System III (1981), the Bourne shell didn't implemented the test utility as a builtin so only the external binary command implementation was available. There wasn't either a [ command (internal or builtin) until Unix System III so for example under Unix Version 7 you had to type:

if test something ; then
…

instead of:

if [ something ] ; then
…

[ is actually more commonly known as test command. Typical use of this command is simply to evaluate expressions and return their condition - true or false. It is often used in if-then-else-fi statements, although it can be used outside of if statements to conditionally run other commands via shell's && or || operators, like so.

$ [ -e /etc/passwd  ] && echo "File exists"
File exists

$ test -e /etc/passwd && echo "File exists"
File exists

More specifically, evaluation is communicated to other commands via exit status. Some programs may choose to output exit status to signify different types of events - program completing successfully, an error of particular type occurring during execution, or syntax errors. In the case of the test command, there are 0 signifies true, and 1 signifies false. As Stephan pointed out, syntax errors produce exit status of 2.

Its location depends on your system, and it also explains why you didn't see man page when you did man [. For instance, on FreeBSD it is under /bin. On Linux (or in my particular case, Ubuntu 16.04) it is in /usr/bin/. If you do man [ or man test on a Linux system, you will see same documentation open. It's also important to note that your shell may have its own implementation of test.

It should also be noted that this command has issues, which Korn shell's implementation (commonly known as "conditional expression" reference with double square brackets, [[ "$USER" = "root" ]] ) seeks to resolve. This feature also used by other shells such as bash and zsh.

Tags:

Shell

Test