1. Introduction
It’s common for developers to call one shell script from another. This could be for organizational purposes or to make a script more reusable. For example, if we have a script that deletes some unused files, we can call it from inside other scripts as a clean-up step to optimize disk space usage.
In this tutorial, we’ll see how we can call a script from inside another script and compare the pros and cons of the different ways we can do this.
2. Prerequisites
Before we get into the details of how to call our script, we need to do two things. The first is adding the shebang, and the second is making the file executable. In the next sections, we’ll see why we need to do this and how to do it.
2.1. The Shebang
The first thing we need to add to any script that we write is the shebang. We write it in the first line of our script, and it tells the kernel which program to use to run the script.
To write a shebang, we have to follow a specific format. We write “#!” followed by the path of the program that we want to use to run our script. So, for example, if we are writing a bash script, this will be our shebang:
#! /bin/bash
Here /bin/bash is the path to the bash executable in most cases.
The shebang is not strictly necessary for the script to work. This is because the default behavior of the kernel is to use the same program that was used to launch the script to run that script. However, it’s really a best practice to add the shebang in order to avoid many errors that could come up later and to make our script more portable and robust.
2.2. Make the File Executable
Unlike the shebang, it’s mandatory to make the file executable so that we can call it from another script. To check whether the file is executable, we can run this in the terminal:
$ ls -l
This command shows the details of the files present in the current directory.
As an example, we have created a directory containing two scripts (script1 and script2). Let’s run the previous command to see if our scripts are executable:
$ ls -l
total 0
-rwxr-xr-x. 1 root root 0 Jan 27 15:26 script1
-rw-r--r--. 1 root root 0 Jan 27 15:26 script2
The key values important to us from the previous output are rw-r–r– and rwxr-xr-x, that are to the left of the file names. The r stands for read, w for write, and x for executable. Knowing that, we can see that script1 is executable while script2 is not.
We’ll use the chmod command to make script2 executable:
$ chmod +x script2
This adds the x to script2 and make it executable. Let’s check again to make sure it’s now executable:
$ ls -l
total 0
-rwxr-xr-x. 1 root root 0 Jan 27 15:26 script1
-rwxr-xr-x. 1 root root 0 Jan 27 15:26 script2
As we can see, script2 is now executable, and we can now call it from script1.
3. Run Script in a New Process
When we call script2 from script1, there are two ways in which script2 can be executed.
The first one is that script2 is executed in a new separate process, and then the result is passed to script1 in its original process. The second way is that script2 is executed in the same original process as script1.
The advantage of the second way is that both scripts will have access to all the variables and functions defined in both of them. Also, this could lead to better performance as the system won’t need to create a new process to run the second script.
Let’s see the contents of the scripts that we’ll be using in this tutorial:
$ cat script1
#!/bin/bash
echo "first script was called"
x="1"
$ cat script2
#!/bin/bash
echo "second script was called"
echo $x
Next, we’ll see how to call script2 from script1.
3.1. The bash Command
The first command we’ll use is the bash command. This makes the kernel use the Bash program to run our script. Let’s add this line at the end of script1:
bash script2
Now let’s call script1 to see the output:
$ ./script1
first script was called
second script was called
At this point, we can see that we’re able to call script2 from inside script1 as we wanted.
However, the second script was not able to print the value of x. This is because it wasn’t able to see it as x was defined in the first script, and it was running in a separate process.
3.2. Call Script as a Normal Command
Now let’s replace the last line from script1 that contains “bash script2“, with the path to script2:
./script2
When we run script1, we’ll see this output:
$ ./script1
first script was called
second script was called
We can see that the output is exactly the same as the previous command, which is what we expected.
When we call the script without choosing a certain shell to run it, it’s run using the program in the shebang. Since our shebang contains the Bash program, the kernel used it to run the script and produced the exact same output as the previous command where we explicitly choose to run our script using Bash.
4. Run the Script in the Same Process
If we want a script to have access to variables and functions defined in another script, we can use the source command.
The source command acts as if we copied the text from the script that was given to it as a parameter to the script in which it’s called.
Next, we will see an example that will help us better understand this.
In the last line of script1, let’s add the source command before the path to scipt2:
source ./script2
Now, let’s run it:
$ ./script1
first script was called
second script was called
1
We can see that script2 was able to see the variable $x and print its value. This is because the source command acted as if we copied the text in script2 to script1 and then ran script1. Thus, all the code was running in the same process, and the script was able to print the variable successfully.
5. Conclusion
In this article, we discussed how to call a script from another script. This is a useful technique that we can use in many applications.
Additionally, we compared different ways to do this and understood the difference between them. Depending on the use case, some commands may be more suitable than others. So, in the end, it’s up to us to choose the command that will best satisfy our needs.