NeuroAgent

Execute One Shell Script from Another: Complete Guide

Learn multiple methods to call one shell script from another including source, direct execution, bash command, and function sourcing. Understand advantages, disadvantages, and best practices for each approach with practical examples.

How to call one shell script from another shell script?

I have two shell scripts, a.sh and b.sh. How can I call b.sh from within the shell script a.sh? What are the different methods to execute one shell script from another, and what are the advantages and disadvantages of each approach?

NeuroAgent

There are several methods to call one shell script from another in Linux/Unix systems. The most common approaches include using the source or . command, executing the script directly with ./script.sh, using the bash command, or sourcing the script within a function. Each method has different implications for variable scope, execution context, and error handling.

Contents


Using the source or . Command

The source command (or its equivalent .) executes the script within the current shell context rather than creating a new subshell. This means that variables and functions defined in the sourced script become available in the calling script.

Syntax:

bash
source b.sh
# or
. b.sh

Advantages:

  • Variable Preservation: Variables and functions defined in b.sh remain accessible in a.sh
  • Performance: No subprocess creation overhead
  • Clean Exit Codes: Exit status is properly propagated
  • Less Memory Usage: No additional shell process is started

Disadvantages:

  • Namespace Pollution: All functions and variables from b.sh pollute the current shell’s namespace
  • Debugging Complexity: Harder to trace execution flow when multiple scripts are sourced
  • Risk of Overwriting: May overwrite existing variables or functions in the calling script

Example:

bash
#!/bin/bash
# a.sh
echo "Starting a.sh"
source b.sh
echo "Variable from b.sh: $MY_VAR"
echo "Function from b.sh: $(my_function)"
echo "Exiting a.sh"

As explained in shell scripting documentation, when you source a script, the environment variables and functions become available in the current shell context, which is particularly useful for maintaining state between script calls.


Direct Execution with ./script.sh

This is the most straightforward method where you execute the second script as a separate process.

Syntax:

bash
./b.sh
# or
/path/to/b.sh

Advantages:

  • Isolation: Runs in a clean, isolated environment
  • No Namespace Pollution: Variables and functions from b.sh don’t affect a.sh
  • Easier Debugging: Separate processes make it easier to trace execution
  • Parallel Execution: Can be run in background with &

Disadvantages:

  • Variable Scope: Variables set in b.sh are not available in a.sh
  • Performance Overhead: Creates a new shell process
  • Exit Code Handling: Need to explicitly check exit codes
  • Memory Usage: Additional process consumes more memory

Example:

bash
#!/bin/bash
# a.sh
echo "Starting a.sh"
./b.sh
echo "Exit code from b.sh: $?"
echo "Exiting a.sh"

According to Techsive’s guide, this method is especially useful when you need to test scripts in a specific shell, or when the execution permission can’t be changed for some reason.


Using the bash Command

This method explicitly calls bash to execute the script, providing more control over the shell environment.

Syntax:

bash
bash b.sh
# or
/bin/bash b.sh

Advantages:

  • Shell Control: Can specify different shell versions
  • Isolation: Clean execution environment
  • Argument Passing: Easy to pass arguments to the script
  • Security: Can be used with restricted shells

Disadvantages:

  • Still Isolated: Variables not shared between scripts
  • Additional Process: Creates another shell process
  • Configuration Differences: May behave differently than current shell
  • Path Dependency: Requires bash to be available in the specified path

Example:

bash
#!/bin/bash
# a.sh
echo "Starting a.sh"
bash b.sh
echo "Exit code from b.sh: $?"
echo "Exiting a.sh"

The Bash Wikipedia entry explains that any startup file can execute commands from any other file, and scripts written in conformance with POSIX guidelines should be executable by any shell system application.


Sourcing Scripts in Functions

This approach combines the benefits of sourcing with better namespace management by containing the sourced script within a function.

Syntax:

bash
load_b_script() {
    source b.sh
}
load_b_script

Advantages:

  • Namespace Control: Variables and functions are contained within the function scope
  • Selective Loading: Can conditionally load scripts
  • Cleaner Interface: Provides a clear API for script interaction
  • Error Handling: Better error handling capabilities

Disadvantages:

  • Complexity: More complex to implement and maintain
  • Variable Access: Need to explicitly export variables to access them outside
  • Debugging Challenges: Can be harder to debug when errors occur

Example:

bash
#!/bin/bash
# a.sh
echo "Starting a.sh"

load_b_script() {
    source b.sh
    # Export needed variables
    export MY_VAR
}

load_b_script
echo "Variable from b.sh: $MY_VAR"
echo "Exiting a.sh"

Best Practices and Recommendations

When to Use Each Method:

  1. Use source/. when:

    • You need to share variables between scripts
    • You want to define reusable functions
    • Performance is critical
    • You’re building a modular script collection
  2. Use direct execution (./script.sh) when:

    • You need complete isolation
    • The script should not affect the calling script’s environment
    • You want to run scripts in parallel
    • Security is a concern (less risk of variable injection)
  3. Use bash script.sh when:

    • You need to specify a particular shell version
    • You want to pass arguments easily
    • You’re working with restricted shell environments
    • You need better control over the execution environment

Performance Considerations:

As noted in AttuneOps’ Shell Automation Essentials, each external call adds overhead, so you should use shell constructs like loops and conditionals to do more within the script itself when possible.

Code Organization Tips:

  • Modular Design: Break large scripts into smaller, focused scripts
  • Clear APIs: Define clear interfaces between scripts when using sourcing
  • Error Handling: Always check exit codes when executing external scripts
  • Documentation: Document dependencies and expected behaviors between scripts

Error Handling and Debugging

Exit Code Handling:

bash
#!/bin/bash
# a.sh
./b.sh
if [ $? -ne 0 ]; then
    echo "Error executing b.sh"
    exit 1
fi

Debug Mode:

bash
#!/bin/bash
# a.sh
set -x  # Enable debugging
source b.sh
set +x  # Disable debugging

Error Handling Patterns:

bash
#!/bin/bash
# a.sh

# Method 1: Check exit code
./b.sh
if [ $? -ne 0 ]; then
    echo "b.sh failed"
    exit 1
fi

# Method 2: Use && operator
./b.sh && echo "Success" || echo "Failed"

# Method 3: Custom error function
error_handler() {
    echo "Error in $1 with exit code $2"
    exit $2
}

./b.sh || error_handler "b.sh" $?

Conclusion

Key Takeaways:

  1. Source/. Command: Best for sharing variables and functions, but pollutes namespace
  2. Direct Execution: Provides isolation but doesn’t share variables, has performance overhead
  3. Bash Command: Offers shell control but still creates isolation
  4. Function Sourcing: Balances namespace control with shared functionality

Practical Recommendations:

  • For shared configuration and utilities, use source/. with clear naming conventions
  • For independent operations, use direct execution with proper error handling
  • Consider the trade-offs between performance and isolation based on your specific use case
  • Always implement proper error handling regardless of the method chosen
  • Document script dependencies and expected behavior clearly

Related Questions:

  • Q: How can I pass arguments to the called script?
    A: Use ./b.sh arg1 arg2 or bash b.sh arg1 arg2

  • Q: How can I return values from the called script?
    A: Use echo/print in the called script and capture with result=$(./b.sh)

  • Q: How can I run scripts in parallel?
    A: Use ./b.sh & for background execution or process management tools

Choose the method that best fits your specific requirements for variable sharing, performance, and isolation. Each approach has its place in shell scripting, and understanding these differences will help you write more robust and maintainable scripts.

Sources

  1. How to Execute .SH Files on Ubuntu and Other Linux Distros - Techsive
  2. Shell Scripting · ArchiDep
  3. Bash (Unix shell) - Wikipedia
  4. Shell Automation Essentials: Tools, Tips, and Best Practices - AttuneOps
  5. The Unix Shell: Summary and Setup - Software Carpentry