Difference between +x and ./<script> and sh ./<script>
Solution 1:
If you use
sh ./<script>.run
/bin/sh
(usually a Bourne shell) will used to run the script. Of course this only works if the script is written for Bourne shell. Sometimes shell scripts for Linux require Bash instead of Bourne shell, so this may not work even if it is a shell script.
If you use
./<script>.run
the kernel looks at the shebang line to find out which program to use to run the program. So this works even if it is a Bash, Perl, Python or some other script.
Thus this is usually the preferred way to run a script.
Solution 2:
As long as it's a sh
(Dash, or equivalent) shell script, no, there's no outward difference.
The problem is .run
doesn't guarantee that's the case. It could be binary. It could be Bash or Python or PHP or whatever; they all have a shell script hash-bang. If you blindly force it through sh
, who knows what could happen. It'll probably error-out but it could accidentally run harmful code before getting that far.
By chmod
ding it (to enable the execution permission bit) and then running it ./script.run
, you give it the best possible possibility of running. If it's a shell script, its hash-bang will be parsed properly and if it's a binary executable, it'll just run natively.
Solution 3:
The two methods can often act the same but are very different.
sh ./script
runs the sh
command with an argument ./script
, which happens to execute the given script.. even if the script is not actually a sh
script (bad)
./script
executes the given file. It does this by looking for the "shebang" line to determine what command to run. If unspecified it uses sh
(this the two methods act the same sometimes), but often a different interpreter is specified..
For example, if filename
contains the following:
#!/usr/bin/python
print "This is a Python script!"
..then the two commands are very different:
$ sh script
script: line 3: print: command not found
$ chmod +x script
$ ./script
This is a Python script!
If there is no shebang line, the two are the same:
$ cat script
echo "This is an sh script"
$ sh ./script
This is an sh script
$ ./script
This is an sh script
Solution 4:
One important difference is if your hashbang line has parameters. For example, if the script starts with
#!/bin/bash -e
...and you run it externally using sh
or bash
, that line will be interpreted as a comment and ignored, so the -e
parameter (exit on failure) won't be processed. So, given the following script:
#!/bin/bash -e
echo Hello
false
echo goodbye
The output for ./script
will be just "Hello", but the output for sh script
will be Hello
followed by goodbye
, which was probably not intended.
This, by the way, is why you should always use a separate set -e
statement (it's a good idea anyway - more often than not, if there's a problem mid-script, you wouldn't want it to be ignored).