In Ubuntu 16.04.3, I have a very simple bash script:
test.sh
[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0
When I call it as the non-root user me
or as root
, it works as expected. If I use sudo ./test.sh
, it complains about a syntax error:
$ ./test.sh
true
me /bin/bash ./test.sh
$ sudo su
# ./test.sh
true
root /bin/bash ./test.sh
# exit
$ sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh
What could be causing this? How can I fix it so that me
can use this script both normally and with sudo
?
Every script begins with a Shebang, without it the shell starting your script doesn't know which interpreter should run your script1 and might – as in the case of
sudo ./script.sh
here – run it withsh
, which in Ubuntu 16.04 is linked todash
. The conditional expression[[
is abash
compound command, sodash
doesn't know how to handle it and throws the error you encountered.The solution here is to add
as the first line of your script. You may get the same result when you call it explicitly with
sudo bash ./script.sh
, but a shebang is the way to go.To check which shell runs your script, add
echo $0
to it. That's not the same asecho $SHELL
, citing wiki.archlinux.org:1: As you started
./test.sh
withbash
it just assumedbash
, the same goes for thesudo su
subshell.As @dessert explained, the problem here is that your script doesn't have a shebang line. Without a shebang,
sudo
will default to attempting to run the file using/bin/sh
. I couldn't find it documented anywhere, but I confirmed by checking thesudo
source code where I found the following in the filepathnames.h
:This means "set if the variable
_PATH_BSHELL
isn't defined, set it to/bin/sh
". Then, in theconfigure
script included in the source tarball, we have:This loop will look for
/bin/bash
,/usr/bin/sh
,/sbin/sh
,/usr/sbin/sh
or/bin/ksh
and then sets the_PATH_BSHELL
to whichever was found first. Since/bin/sh
was the first in the list and it exists,_PATH_BSHELL
is set to/bin/sh
. The result of all this is that the default shell ofsudo
unless otherwise defined is/bin/sh
.So,
sudo
will default to running things using/bin/sh
and, on Ubuntu, that is a symlink todash
, a minimal POSIX compliant shell:The
[[
construct is a bash feature, it isn't defined by the POSIX standard and isn't understood bydash
:In detail, in the three invocations you tried:
./test.sh
No
sudo
; in the absence of a shebang line, your shell will try to execute the file itself. Since you are runningbash
, this will effectively runbash ./test.sh
and work.sudo su
followed by./test.sh
.Here, you are starting a new shell for the user
root
. This will be whatever shell is defined in the$SHELL
environment variable for that user and, on Ubuntu, root's default shell isbash
:sudo ./test.sh
Here, you are letting
sudo
execute the command directly. Since its default shell is/bin/sh
as explained above, this causes it to run the script with/bin/sh
, which isdash
and it fails sincedash
doesn't understand[[
.Note: the details of how
sudo
sets the default shell seem to be a bit more complex. I tried changing the files mentioned in my answer to point to/bin/bash
butsudo
was still defaulting to/bin/sh
. So there must be some other places in the source code where the default shell is defined. Nevertheless, the main point (thatsudo
defaults tosh
) still stands.