How to call one shell script from another shell script?

Learn how to call one shell script from another shell script? with practical examples, diagrams, and best practices. Covers bash, shell development techniques with visual explanations.

How to Call One Shell Script from Another Shell Script

How to Call One Shell Script from Another Shell Script

Learn the different methods to execute a shell script from within another, understanding their implications for variable scope and execution environment.

Executing one shell script from another is a common practice in shell scripting, allowing for modularity, reusability, and better organization of your code. There are several ways to achieve this, each with distinct behaviors regarding how variables, functions, and the execution environment are handled. This article will explore the most common methods: sourcing, executing as a child process, and using the exec command, providing practical examples and best practices.

Method 1: Sourcing ('. ' or 'source')

Sourcing a script means that the commands within the called script are executed in the current shell environment. This is particularly useful when you want to share variables, functions, or aliases between scripts. Any variables set or modified in the sourced script will affect the calling script's environment. This method is often used for configuration files or utility functions.

#!/bin/bash

# caller.sh

echo "Caller: Initial value of MY_VAR is $MY_VAR"

# Source the script
source ./callee.sh

echo "Caller: Value of MY_VAR after sourcing is $MY_VAR"

# Call a function defined in callee.sh
hello_from_callee

echo "Caller: After callee, MY_VAR is $MY_VAR and NEW_VAR is $NEW_VAR"

The calling script (caller.sh) sourcing another script.

#!/bin/bash

# callee.sh

MY_VAR="Hello from Callee"
NEW_VAR="I am a new variable"

function hello_from_callee() {
  echo "Callee: Hello from a function in callee.sh!"
}

echo "Callee: MY_VAR set to $MY_VAR"

The sourced script (callee.sh) defining variables and a function.

Method 2: Executing as a Child Process ('./script.sh' or 'bash script.sh')

When you execute a script using ./script.sh (assuming it's executable) or bash script.sh, it runs in a new subshell. This means it gets its own separate environment, which is a copy of the parent's environment at the time of execution. Any variables or functions defined or modified within the child script will not affect the parent script's environment. This method provides isolation and is the most common way to run independent scripts.

#!/bin/bash

# parent.sh

PARENT_VAR="I am from parent"
export EXPORTED_VAR="I am exported from parent"

echo "Parent: Initial PARENT_VAR = $PARENT_VAR"
echo "Parent: Initial EXPORTED_VAR = $EXPORTED_VAR"

# Execute the child script
./child.sh

echo "Parent: PARENT_VAR after child execution = $PARENT_VAR (should be unchanged)"
echo "Parent: EXPORTED_VAR after child execution = $EXPORTED_VAR (should be unchanged)"
echo "Parent: CHILD_VAR after child execution = $CHILD_VAR (should be empty)"

The parent script (parent.sh) executing a child script.

#!/bin/bash

# child.sh

echo "Child: PARENT_VAR received = $PARENT_VAR (should be empty)"
echo "Child: EXPORTED_VAR received = $EXPORTED_VAR (should be 'I am exported from parent')"

PARENT_VAR="Modified by child"
CHILD_VAR="I am from child"

echo "Child: PARENT_VAR modified to = $PARENT_VAR"
echo "Child: CHILD_VAR set to = $CHILD_VAR"

The child script (child.sh) modifying variables locally.

Method 3: Using 'exec'

The exec command replaces the current shell process with the specified command or script. When you use exec to call another script, the calling script terminates and the called script takes over its process ID. The calling script does not resume after the exec command. This is useful when you want to pass control completely to another script without returning.

#!/bin/bash

# first_script.sh

echo "First Script: Starting... PID is $$"

VAR_FROM_FIRST="Hello from first script"
export VAR_FROM_FIRST

echo "First Script: About to exec second_script.sh"

exec ./second_script.sh

echo "First Script: This line will NEVER be reached."

The first script (first_script.sh) using exec to hand over control.

#!/bin/bash

# second_script.sh

echo "Second Script: Starting... PID is $$"
echo "Second Script: Received VAR_FROM_FIRST = $VAR_FROM_FIRST"

FINAL_VAR="I am from second script"

echo "Second Script: Done."

The second script (second_script.sh) taking over the process.

A flowchart diagram comparing three methods of calling shell scripts: Sourcing, Child Process, and Exec. Sourcing shows commands running in the same shell environment, sharing variables. Child Process shows a new subshell being created, inheriting parent's exported variables but not affecting parent's environment. Exec shows the parent process being replaced entirely by the child script. Use distinct colors for each method and clear arrows indicating control flow and variable scope.

Comparison of script calling methods: Sourcing, Child Process, and Exec.

Summary and Best Practices

Choosing the right method depends on your specific needs:

  • Sourcing (. or source): Use when you need to share variables, functions, or configurations directly with the calling script's environment. Ideal for library scripts or environment setup.
  • Child Process (./script.sh or bash script.sh): Use for executing independent tasks or modules. This provides excellent isolation, preventing unintended side effects on the calling script. It's the most common and safest method for general script execution.
  • exec: Use when you want to completely hand off control from the current script to another, and the current script should not resume execution. This is less common but useful for specific scenarios like daemonizing processes or launching a new application from a wrapper script.

Always consider the scope of variables and the desired execution flow when deciding how to call one shell script from another. Understanding these distinctions is key to writing robust and maintainable shell scripts.