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