How to pass arguments to a script invoked by source command?

Expanding on the (currently accepted) answer from redneb...

TL;DR Need to source a script with no positional arguments within another script? try function DoSource() { source test.sh ; } ; DoSource instead of just source test.sh.

sourceing a script with no arguments within another script

The excerpt from Bash manual in the question shows the details of how the positional parameters are assigned to the sourced script. In particular, if the source command does not specify any argument, it is assigned the ones from the calling environment.

A consequence is that it may be troublesome to source a script passing no arguments within another script. For example, let's use redneb example as test.sh:

echo "I was given $# argument(s):"
printf "%s\n" "$@"

sourced within another script userScript.sh, which is e.g. the one-liner:

source test.sh

When running an example like above:

$ bash userScript.sh a 'b c'
I was given 2 argument(s):
a
b c

test.sh inherits userScript.sh positional arguments... which now is not what I want (if I did, I could have used source test.sh "$@").

I have found the following to be a useful workaround: encapsulate the source command into a Bash function. The new userScript.sh looks like:

function DoSource() { source test.sh ; }
DoSource

reports:

$ bash userScript.sh a 'b c'
I was given 0 argument(s):

Note that specifying an empty argument (source test.sh '') is not equivalent, since the empty argument would be passed to test.sh.

If the sourcing script is also expected to be sourced

If userScript.sh itself is supposed to be sourced, then one probably does not want to leave DoSource() around. In that case, the simple solution is self destruction:

function _userScript_sh_DoSource() { source test.sh ; unset "$FUNCNAME" ; }
_userScript_sh_DoSource

for one-time-only usage (function name has been chosen to reduce the chance of name conflicts); or a unset _userScript_sh_DoSource command can be places after _userScript_sh_DoSource is not needed any more.

Flexible variant for multiple use

A more complex variant of DoSource():

function DoSource() { local ScriptName="$1" ; shift ; source "$ScriptName" ; }
DoSource test1.sh
DoSource test1.sh "$@"
DoSource test2.sh

can be used as a "drop-in" replacement for source, with the only difference being that when no positional argument is specified for the script to be sourced, source inherits them, while DoSource uses none. Note however that DoSource is a function and as such behaves differently from source in other aspects (e.g. stack call, FUNCNAME, ...).


Create a file test.sh with the following contents:

echo "I was given $# argument(s):"
printf "%s\n" "$@"

and then source it from an interactive shell session:

$ source ./test.sh a 'b c'
I was given 2 argument(s):
a
b c

so you access the arguments just like you would do in a regular bash script, with $@ or $1, $2, $3, etc.

For comparison, run it as a regular script:

$ bash ./test.sh a 'b c'
I was given 2 argument(s):
a
b c

Tags:

Linux

Bash