Here is my script:
#!/bin/sh
echo "$PATH"
[ "$UID" -eq 0 ] || exec sudo "$0" "$@"
echo "$UID"
echo "$SUDO_USER"
If I run this script by ./test.sh
, this is the result:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
./test.sh: 3: [: Illegal number:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
./test.sh: 3: [: Illegal number:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
./test.sh: 3: [: Illegal number:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
...
And it keeps printing the same thing.
If I run by sh test.sh
, then the result is:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
test.sh: 3: [: Illegal number:
sudo: test.sh: command not found
And just print once. (I've installed sudo.)
As I know, ./
and sh
command are the same. And sh
is linked to dash. So how to explain this problem?
System info:
Linux version 5.19.0-32-generic (buildd@lcy02-amd64-026) (x86_64-linux-gnu-gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #33~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC
Explain the reason that ./
and sh
have different results when executing the same script.
2
Answers
The script is recursively executing itself, because your
UID
is not set.The difference between the methods:
./test.sh
executes the file itself (if shebang is valid)sh test.sh
executes shell and passes file name as argumentThe positional parameter
$0
reflects the file name of execution./test.sh
test.sh
the latter one misses the path in file name, your script is therefore looking for non-existing file in
PATH
(/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin)you can use
realpath
to determine the file path:When you run
sh test.sh
, then$0
istest.sh
so thensudo "$0" "$@"
command becomessudo test.sh
.There is no such command as
test.sh
in PATH. You can run./test.sh
orsh test.sh
likesudo ./test.sh
orsudo sh test.sh
, but not plaintest.sh
.