Proper Argument Passing Between Bash Scripts: Solving Issues with Spaces and Quotes

Dec 03, 2025 · Programming · 8 views · 7.8

Keywords: Bash scripting | argument passing | quoting

Abstract: This article provides an in-depth analysis of how to correctly handle argument passing between Bash scripts when arguments contain spaces and quotes. Through a detailed examination of a common error case, it explains the importance of quoting in parameter expansion, compares different argument passing methods such as $@, "$@", $*, and "$*", and offers best-practice solutions. The article also discusses strategies for handling arguments in complex scenarios like remote execution, helping developers avoid argument splitting errors and ensure data integrity.

Problem Background and Error Analysis

In Bash scripting, it is common to call one script from another and pass arguments. When arguments contain spaces or special characters, improper handling can lead to incorrect argument splitting. This article analyzes a typical case: when TestScript1 calls TestScript2, it intends to pass two arguments ("Firstname Lastname" and "testmail@example.com"), but the actual output shows the arguments split into three ("Firstname", "Lastname", and "testmail@example.com").

Core Issue: Quoting in Parameter Expansion

The root cause lies in the code within TestScript1 that calls TestScript2: ./testscript2 $1 $2. In Bash, unquoted parameter expansion undergoes word splitting and pathname expansion. When $1 has the value "Firstname Lastname", Bash splits it into two separate words "Firstname" and "Lastname", causing TestScript2 to receive three arguments instead of the expected two.

Solution: Properly Quoting Arguments

The best solution is to wrap each parameter variable in double quotes when passing arguments. Modify the call in TestScript1 to: ./testscript2 "$1" "$2". This treats each argument as a complete string, preventing Bash from splitting it. Example code:

echo "TestScript1 Arguments:"
echo "$1"
echo "$2"
echo "$#"
./testscript2 "$1" "$2"

This modification ensures that TestScript2 receives exactly the same arguments as TestScript1, including spaces and quotes.

Comparison of Argument Passing Methods

In addition to quoting each argument individually, you can use "$@" to pass all arguments. Unlike $@ (without quotes), "$@" treats each argument as an independent quoted string, avoiding splitting. Example:

echo "TestScript1 Arguments:"
for arg in "$@"; do
    echo "${arg}"
done
echo "nb of args: $#"
./testscript2 "$@"

In contrast, $* and "$*" combine all arguments into a single string, which is generally unsuitable for scenarios requiring argument independence.

Argument Handling in Complex Scenarios

In complex scenarios involving remote execution or multi-layer calls, argument passing requires extra attention. For example, when executing scripts remotely via SaltStack, you might need to construct argument strings. One approach is to use a loop to build quoted argument strings:

theargs="'$1'"
shift
for i in "$@"; do
    theargs="${theargs} '$i'"
done
salt 'remote host' cmd.run "./testscript2 ${theargs}"

This method ensures each argument is correctly parsed in the remote environment, but note that nested quotes can introduce parsing complexities.

Practical Recommendations and Summary

When passing arguments in Bash scripts, always wrap parameter variables in double quotes (e.g., "$1", "$@") to avoid word splitting. For scenarios requiring all arguments, prefer "$@" over $@ or $*. In complex call chains, consider explicitly constructing argument strings to ensure correct parsing across environments. By following these practices, you can significantly reduce argument handling errors and improve script robustness and maintainability.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.