Reputation: 1445
I am writing a bash script that takes in some optional parameters. I want to translate them and pass them to another script. However, I'm having a hard time passing the optional parameters gracefully.
Here's a outline of what I managed to get working in pseudocode:
a.sh:
if arg1 in arguments; then
firstArg="first argument"
fi
if arg2 in arguments; then
secondArg="second argument"
fi
./b.sh $firstArg $secondArg "default argument"
Note the spaces in the arguments.
b.sh:
for arg in "$@"
do
echo $arg
done
I want to call b.sh
, optionally with firstArg
and secondArg
and a default argument like so:
./b.sh $firstArg $secondArg "default argument"
The problem with this is that if $firstArg
or $secondArg
are strings with spaces, they will be represented as multiple arguments, and the output will be something like:
first
argument
second
argument
default argument
Okay, that's easy to fix, let's capture the entire string of the arguments by adding quotes around it like so:
./b.sh "$firstArg" "$secondArg" "defaultArg"
Problem is if, for example, firstArg
is not set, it results in a blank line (as it will interpret ""
as a parameter), so the output will be something like:
(blank line here)
second argument
defaultArg
I've also tried constructing a string and passing it to the shell script, but it doesn't seem to work that way either (it interprets the whole string as an argument, even if I add separate the arguments with quotes).
Note that calling b.sh
from my command line with the arguments quoted works fine. Is there a way to mimic how this works from within a bash script?
Upvotes: 9
Views: 4706
Reputation: 295934
If you literally want to copy all arguments given, but add one more:
# this works in any POSIX shell
./b.sh "$@" defaultArg
Alternately, to explicitly pass firstArg
and secondArg
, but only if they exist (note that set-to-an-empty-value counts as "existing" here):
# this works in any POSIX shell
./b.sh ${firstArg+"$firstArg"} ${secondArg+"$secondArg"} defaultArg
If you want to treat set-to-an-empty-value as not existing:
# this works in any POSIX shell
./b.sh ${firstArg:+"$firstArg"} ${secondArg:+"$secondArg"} defaultArg
An alternate approach is to build up an array of arguments:
# this requires bash or another shell with arrays and append syntax
# be sure any script using this starts with #!/bin/bash
b_args=( )
[[ $firstArg ]] && b_args+=( "$firstArg" )
[[ $secondArg ]] && b_args+=( "$secondArg" )
b_args+=( "default argument" )
./b.sh "${b_args[@]}"
If you want something with the same flexibility as the array method, but without the compatibility issues, define a function; within it, you can safely override "$@"
without impacting the rest of the script:
runB() {
set --
[ -n "$firstArg" ] && set -- "$@" "$firstArg"
[ -n "$secondArg" ] && set -- "$@" "$secondArg"
./b.sh "$@" "default argument"
}
Upvotes: 9
Reputation: 45706
Use an array:
args=()
if [ ... ]; then
args+=( "first argument" )
fi
if [ ... ]; then
args+=( "second argument" )
fi
./b.sh "${args[@]}" "default argument"
Upvotes: 1