I see there is an executable called "[" in
/usr/bin. What is its purpose?
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
$ 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
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,
[ are equivalent. The
/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
> 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
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
[ 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
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.
[ return only an exit code of
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
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.
cp x y 2>/dev/null && echo cp x y OK || echo cp x y not OK
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
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
test, despite having almost the same syntax:
Finally, to find out what a command is, you can use:
type -a command