1. Overview

Shell scripts are a set of commands saved in a file. We can usually enter the script name at a prompt and have the current shell read and run the commands. Alternatively, we can explicitly invoke a given shell to run the script.

In this tutorial, we’ll learn how the two methods work. In addition, we’ll identify the similarities and differences between them.

2. Example Script

To see both ways to invoke a shell script, we’ll create a simple one under our working directory:

echo Hello from shell script with process id $$;
readlink /proc/$$/exe;

First, our script prints a message that includes its process identifier (PID). This is done via the $$ variable – the PID of the current process. Moreover, the script calls the readlink command to print the shell that’s running the script via the /proc pseudo-filesystem.

Now, let’s see both methods to invoke this simple script.

3. Invoking a Shell Script Directly From the Command-Line

We can invoke a shell script directly from the command prompt. Thus, the shell we’re currently using executes the commands that the script contains.

3.1. Handling Permissions

Before executing a script directly, we should set its executable bit to 1:

$ chmod u+x myscript

Here, we add the execute permission with the chmod command. If we don’t, the shell might later return a message about denied permissions.

3.2. How the Shell Locates the Script

Now, let’s try to execute the script via its name:

$ myscript
myscript: command not found

As we can see, the shell failed to locate our script. This happened because of the way shells try to locate the script’s file.

First, the shell checks if we’ve entered the file path of the script by checking if the input contains any slashes. If it does, the shell tries to locate the script in the corresponding directory.

If we haven’t included the path, i.e., there are no slashes, the shell uses the $PATH environment variable. This means that it searches for the shell script file in the paths included in the $PATH variable.

Since our working directory isn’t included in the $PATH variable, and we didn’t include a path to the script, the shell failed to locate it.

3.3. Process Handling

Let’s enter the path to the script and invoke it:

$ ./myscript
Hello from shell script with process id 4337
/usr/bin/bash

This time, the shell found the script in our working directory and ran it. Of course, we could’ve also used the full path to the script instead. In any case, we see the process ID and the shell that executed the script, which in our case is Bash.

Let’s compare the process ID that the script printed to the process ID of our terminal session:

$ echo $$
1375

As can be seen, our main shell runs in a different process. This happens because the shell created a subshell in a child process to run the script.

3.4. Shebang

A shebang references an interpreter like Bash and Sh. It starts with the #! characters followed by the absolute path of an interpreter. Moreover, we place it in the first line of a script.

If we don’t include a shebang, the interpreter of our current interactive session is used. Let’s add a shebang to the top of our script:

#!/bin/dash

So, we set the Dash shell to interpret our shell script. Now, let’s run the script again:

$ ./myscript
Hello from shell script with process id 4380
/usr/bin/dash

Indeed, we can see that Dash executed the commands of our script.

4. Invoking Bash to Run a Script

Another way to execute a script is to invoke the bash or respective shell command with the script’s filename. In our case, Bash runs the script’s commands instead of the interactive shell that we use.

Furthermore, we don’t need to set the execute permission for the file since the executable file will be the shell we invoke, e.g., bash, instead of the script itself. The script is an argument to the bash command.

To demonstrate this, let’s switch to another shell and execute our script:

$ /bin/dash
$ ./myscript
Hello from shell script with process id 3155
/usr/bin/dash
$ bash myscript
Hello from shell script with process id 4372
/usr/bin/bash
$ echo $$
4371

In the example above, we first enter the /bin/dash shell*.* Then, we invoke the script directly, showing that it runs with Dash as its shell. Next, we invoke bash to run the script. As expected, the script runs successfully via the bash shell.

Furthermore, it prints a PID that’s different from the PID of the current shell session. This means that the script ran in another process.

Finally, the bash command ignores any shebang we include in our script. This means that this method of invocation makes Bash run the commands in every case, even if the shebang points to another interpreter.

5. Conclusion

In this article, we learned two ways to invoke a shell script. The first is to invoke it directly from an interactive shell. The second is to invoke a shell, like Bash, non-interactively to run the commands. Finally, we identified the similarities and differences between them.