What is the purpose of square bracket executable

In most cases, [ is a shell builtin and is equivalent to test. However, like test, it also exists as a standalone executable: that's the /bin/[ you saw. You can test this with type -a [ (on an Arch Linux system, running bash):

$ type -a [
[ is a shell builtin
[ is /bin/[

So, on my system, I have two [: my shell's builtin and the executable in /bin. The executable is documented in man test:

TEST(1)                          User Commands                         TEST(1)

NAME
       test - check file types and compare values

SYNOPSIS
       test EXPRESSION
       test

       [ EXPRESSION ]
       [ ]
       [ OPTION

DESCRIPTION
       Exit with the status determined by EXPRESSION.

[ ... ]

As you can see in the excerpt of the man page quoted above, test and [ are equivalent. The /bin/[ and /bin/test commands are specified by POSIX which is why you'll find them despite the fact that many shells also provide them as builtins. Their presence ensures that constructs like:

[ "$var" -gt 10 ]  && echo yes

will work even if the shell running them doesn't have a [ builtin. For example, in tcsh:

> which [
/sbin/[
> set var = 11
> [ "$var" -gt 10 ]  && echo yes
yes

That is used for condition testing in shell scripts. Another name of this program is test:

if [ 1 -lt 2 ]; then ...

That looks like shell grammar but isn't. Usually [ is a shell builtin but probably as fallback it exists as an external command.

See the block "CONDITIONAL EXPRESSIONS" in man bash.


[ is same command as test. On some *nix systems, one is just a link to the other. For example, if you run:

strings /usr/bin/test 
strings /usr/bin/[

you will see the same output.

Most sh-shells/posix-shells include builtin [ and test commands. The same is true for echo. There is both a /bin/echo command and a builtin in most of shells. That it's the reason why sometimes you feel that, for example, echo doesn't work the same way on different systems.

test or [ return only an exit code of 0 or 1. If the test was successful, the exit code is 0.

# you can use [ command but last argument must be ] 
# = inside joke for programmers 
# or use test command. Args are same, but last arg can't be ] :)
# so you can't write 
#    [-f file.txt] because [-f is not command and last argument is not ]
# after [ have to be delimiter as after every commands
[ -f file.txt ] && echo "file exists" || echo "file does not exist"
test -f file.txt && echo "file exists" || echo "file does not exist"
[ 1 -gt 2 ] && echo yes || echo no
test 1 -gt 2  && echo yes || echo no
# use external command, not builtin
/usr/bin/[ 1 -gt 2 ] && echo yes || echo no

You can also use [ with if:

if [ -f file.txt ] ; then
  echo "file exists" 
else 
  echo "file does not exist"
fi
# is the same as
if test -f file.txt  ; then
  echo "file exists" 
else 
  echo "file does not exist"
fi

But you can use if with every command, if is for testing exit code. For example:

cp x y 2>/dev/null && echo cp x y OK ||  echo cp x y not OK

Or, using if:

if cp x y 2>/dev/null ; then
   echo cp x y OK
else
   echo cp x y not OK
fi

You can get the same result using only the test command to test the exit code which is saved to the variable stat:

cp x y 2>/dev/null 
stat=$?
if test "$stat" = 0 ; then
   echo cp x y OK
else
   echo cp x y not OK
fi

You can also use [[ ]] and (( )) for testing, but those are not the same as [ and test, despite having almost the same syntax:

Finally, to find out what a command is, you can use:

type -a command

Tags:

Utilities

Test