Executing Shell Scripts from Within Other Scripts
A common task in shell scripting is to execute one script from within another. This allows you to modularize your code, reuse functionality, and build complex workflows. There are several ways to achieve this, each with its own implications for how the scripts interact with each other and the parent shell environment. This tutorial will cover the most common methods, explaining their differences and use cases.
Methods for Script Execution
Here are the primary ways to call one shell script from another:
-
Direct Execution with Path: This is the simplest approach. If the script you want to execute has execute permissions (using
chmod +x script.sh
), and is either in yourPATH
environment variable or you provide its full or relative path, you can execute it directly:#!/bin/bash echo "Starting main script..." ./another_script.sh # Assuming another_script.sh is in the same directory echo "Main script continues..."
This method launches
another_script.sh
as a separate process. Any variables or functions defined withinanother_script.sh
will not be accessible in the calling script. The scripts operate independently. -
source
Command (or.
): Thesource
command (and its equivalent, the dot.
) executes the contents of the specified script within the current shell process. This is a crucial difference from direct execution.#!/bin/bash echo "Starting main script..." source ./another_script.sh # Or: . ./another_script.sh echo "Main script continues..."
Because the script is executed in the same process, any variables, functions, or aliases defined within
another_script.sh
will be available in the calling script. This is useful for setting up environment variables or defining functions that you want to use throughout your workflow.Important Considerations with
source
:- If
another_script.sh
contains anexit
command, it will also terminate the calling script. - Be mindful of variable name collisions. If both scripts define variables with the same name, the value from the sourced script will overwrite the value in the calling script.
- If
-
bash
Command: You can also execute a script using thebash
command:#!/bin/bash echo "Starting main script..." bash ./another_script.sh echo "Main script continues..."
This is similar to direct execution.
another_script.sh
is launched as a separate process, and variables or functions defined within it are not accessible in the calling script. -
Using Subshells with
exec
: Theexec
command replaces the current shell process with the specified command. To avoid completely replacing your main script’s process, you can executeexec
within a subshell, created using parentheses:#!/bin/bash echo "Starting main script..." ( exec ./another_script.sh ) echo "Main script continues..."
This effectively runs
another_script.sh
in a separate process but contained within the current shell environment.
Choosing the Right Method
The best method depends on your specific needs:
- Independent Processes: If you want to run a script as a separate process without affecting the calling script’s environment, use direct execution with the path or the
bash
command. - Sharing Environment: If you need to share variables and functions between scripts, use the
source
command (or.
). - Controlled Execution: Use subshells with
exec
when you need to run a script within a controlled execution context, minimizing the risk of unintended side effects.
Example
Let’s illustrate with a simple example. Assume we have two scripts: script1.sh
and script2.sh
.
script1.sh:
#!/bin/bash
echo "Starting script1..."
my_variable="Hello from script1"
source script2.sh # Use source to share variables
echo "script1 continues: my_variable = $my_variable"
script2.sh:
#!/bin/bash
echo "Running script2..."
my_variable="Hello from script2"
If you run script1.sh
, the output will be:
Starting script1...
Running script2...
script1 continues: my_variable = Hello from script2
Notice how the value of my_variable
in script1.sh
was overwritten by the value defined in script2.sh
because we used the source
command. If we had used ./script2.sh
, the value of my_variable
in script1.sh
would have remained "Hello from script1".