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 yourPATHenvironment 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.shas a separate process. Any variables or functions defined withinanother_script.shwill not be accessible in the calling script. The scripts operate independently. -
sourceCommand (or.): Thesourcecommand (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.shwill 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.shcontains anexitcommand, 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
-
bashCommand: You can also execute a script using thebashcommand:#!/bin/bash echo "Starting main script..." bash ./another_script.sh echo "Main script continues..."This is similar to direct execution.
another_script.shis launched as a separate process, and variables or functions defined within it are not accessible in the calling script. -
Using Subshells with
exec: Theexeccommand replaces the current shell process with the specified command. To avoid completely replacing your main script’s process, you can executeexecwithin a subshell, created using parentheses:#!/bin/bash echo "Starting main script..." ( exec ./another_script.sh ) echo "Main script continues..."This effectively runs
another_script.shin 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
bashcommand. - Sharing Environment: If you need to share variables and functions between scripts, use the
sourcecommand (or.). - Controlled Execution: Use subshells with
execwhen 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".