61

If script.sh is just something typical like

#!/bin/bash
echo "Hello World!"

Is there a preferred way to run the script? I think you first have to chmod it so it becomes executable?

user72136
  • 611

4 Answers4

76

For your specific script either way will work, except that ./script.sh requires execution and readable bits, while bash script.sh only requires readable bit.


The reason of the permissions requirement difference lies in how the program that interprets your script is loaded:

  • ./script.sh makes your shell run the file as if it was a regular executable.

The shell forks itself and uses a system call (e.g. execve) to make the operating system execute the file in the forked process. The operating system will check the file's permissions (hence the execution bit needs to be set) and forward the request to the program loader, which looks at the file and determines how to execute it. In Linux compiled executables start with an ELF magic number, while scripts start with a #! (hashbang). A hashbang header means that the file is a script and needs to be interpreted by the program that is specified after the hashbang. This allows a script itself to tell the system how to interpret the script.

With your script, the program loader will execute /bin/bash and pass ./script.sh as the command-line argument.

  • bash script.sh makes your shell run bash and pass script.sh as the command-line argument

So the operating system will load bash (not even looking at script.sh, because it's just a command-line argument). The created bash process will then interpret the script.sh because it's passed as the command-line argument. Because script.sh is only read by bash as a regular file, the execution bit is not required.


I recommend using ./script.sh though, because you might not know which interpreter the script is requiring. So let the program loader determine that for you.

hellodanylo
  • 2,433
  • 3
    If the executable bit is not set, you can also run the script by doing ". ./script.sh" – Dog eat cat world Jun 11 '14 at 16:50
  • 2
    @Dog You are correct. The dot is a shortcut for built-in command 'source', which runs the script in the current bash process. So only the readable bit is required. – hellodanylo Jun 11 '14 at 18:35
  • 5
    @Dogeatcatworld while that is true, running . ./script.sh is not the same thing as bash script.sh (or ./script.sh. Consider the script #!/usr/bin/python -Vprint test. – casey Jun 11 '14 at 21:49
  • 14
    Beware that sourcing a script could result in contamination of the interactive session. For example, should a script change the PATH environment variable, this change will affect commands run following the source. This approach should really be reserved for situations where you depend on the side effects (environment setup scripts and the like). For other situations where you can't change the permissions, running the command in the shebang line, following by the script name is the safest approach. – ctt Jun 12 '14 at 00:15
  • 8
    Note that, if you source a script in the current directory, you don’t need to use ./; just say . script.sh. But I agree with the people who discourage using the . command on scripts that weren’t meant to be invoked that way. I’m surprised that nobody mentioned that, if the script contains exit commands, and you source it, it could log you out. A less dire problem would be if the script does a cd, as that would also affect the parent (interactive) shell. – Scott - Слава Україні Jun 12 '14 at 00:43
  • Which option is better/recommended? any pros cons of each approach in terms of performance, log redirection etc – spats Jun 09 '20 at 08:21
23

bash script.sh invokes the script directly using the bash.
./script.sh is using the shebang #!/bin/bash to determine how to execute.

If you really want to know, which binary is executed if you do a bash script.sh you could find out with which bash.

So in your example it makes no difference. Yes, you have to chmod +x script.sh to be able to execute it directly via ./script.sh.

xx4h
  • 2,400
  • 2
    Well, it makes no difference assuming that /bin/bash is the first bash in your $PATH. – cjm Jun 11 '14 at 05:50
  • You're right. And the shebang #!/bin/bash is only working if there is a /bin/bash – xx4h Jun 11 '14 at 05:52
  • Bash (version 4.2.37) on my system executes scripts even without the execution bit set. Why do you say execution bit is required? – hellodanylo Jun 11 '14 at 05:59
  • Yes, execution bit is only needed by invoking via ./script.sh. – xx4h Jun 11 '14 at 06:04
16

Create a file Delete_Self.sh like this:

 #!/bin/rm

 echo I am still here!

Run this script as sh Delete_Self.sh you will see "I am still here!" echoed back.

Make it executable, and run it as ./Delete_Self.sh you will see nothing is echoed back, while the file Delete_Self.sh itself is gone.

So the difference is that:

  • bash script.sh will ignore the #! line, because bash is specified as the program to run script.sh.
  • ./script.sh will read the #! line to determine the program to run script.sh.
Romeo Ninov
  • 17,484
David
  • 171
5

In addition to the other answers, knowing the difference between running a script via ./script.sh (i) and source ./script.sh (ii) is useful - The (i) version creates a new shell in which to run the command, whereas (ii) runs it in the current shell - which can be mandatory if the executable changes environment variables that need to be preserved after the executable exits. For example, to activate a python conda environment the following must be used:

source activate my_env

N.B. Another alternative to source that you may encounter is the . builtin, i.e.

. activate my_env