Reputation: 3618
I'm trying to conditionally pass an argument to a bash script only if it has been set in the calling script and I've noticed some odd behavior. I'm using parameter expansion to facilitate this, outputting an option only if the corresponding variable is set. The aim is to pass an argument from a 'parent' script to a 'child' script.
Consider the following example:
The calling script:
#!/bin/bash
# 1.sh
ONE="TEST_ONE"
TWO="TEST_TWO"
./2.sh \
--one "${ONE}" \
"${TWO:+"--two ${TWO}"}" \
--other
and the called script:
#!/bin/bash
# 2.sh
while [[ $# -gt 0 ]]; do
key="${1}"
case $key in
-o|--one)
ONE="${2}"
echo "ONE: ${ONE}"
shift
shift
;;
-t|--two)
TWO="${2}"
echo "TWO: ${TWO}"
shift
shift
;;
-f|--other)
OTHER=1
echo "OTHER: ${OTHER}"
shift
;;
*)
echo "UNRECOGNISED: ${1}"
shift
;;
esac
done
output:
ONE: TEST_ONE
UNRECOGNISED: --two TEST_TWO
OTHER: 1
Observe the behavior of the option '--two', which will be unrecognised. It looks like it is being expanded correctly, but is not recognised as being two distinct strings.
Can anyone explain why this is happening? I've seen it written in one source that it will not work with positional parameter arguments
, but I'm still not understanding why this behaves as it does.
Upvotes: 2
Views: 66
Reputation: 85550
It is because when you pass $2
as a result of parameter expansion from 1.sh
you are quoting it in a way that --two TEST_TWO
is evaluated as one single argument, so that the number of arguments in 2.sh
result in 4
instead of 5
But that said, using your $2
as ${TWO:+--two ${TWO}}
would solve the problem, but that would word-split the content of $2
if it contains spaces. You need to use arrays.
As a much more recommended and fail-proof approach use arrays as below on 1.sh
as
argsList=(--one "${ONE}" ${TWO:+--two "${TWO}"} --other)
and pass it along as
./2.sh "${argsList[@]}"
or if you are familiar with how quoting rules work (how and when to quote to prevent word-splitting from happening) use it directly on the command line as below. This would ensure that the contents variables ONE
and TWO
are preserved even if they have spaces.
./2.sh \
--one "${ONE}" \
${TWO:+--two "${TWO}"} \
--other
As a few recommended guidelines
getopts()
for more robust argument flags parsingUpvotes: 3