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
.
source
ing 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