10

I tried building a set of arguments in a variable and passing that to a script but the behavior different from what I expected.

test.sh

#!/bin/bash

for var in "$@"; do
  echo "$var"
done

input

usr@host$ ARGS="-a \"arg one\" -b \"arg two\""
usr@host$ ./test.sh $ARGS

output

-a
"arg
one"
-b
"arg
two"

expected

-a
arg one
-b
arg two

Note if you pass the quoted arguments directly to the script it works. I also can work around this with eval but I wanted to understand why the first approach failed.

workaround

ARGS="./test.sh -a "arg one" -b "arg two""
eval $ARGS
3
  • FYI, for var in "$@; do" is the same as for var; do. Commented Sep 25, 2013 at 19:59
  • 2
    eval is not a workaround, it is the way to do this. Commented Sep 29, 2013 at 6:44
  • @EranBen-Natan, using eval compromises security. It's utterly unsuited for situations where data is not hand-written by someone at least as trusted as the software's developer. Commented Jul 16, 2018 at 17:38

1 Answer 1

21

You should use an array, which in some sense provides a 2nd level of quoting:

ARGS=(-a "arg one" -b "arg two")
./test.sh "${ARGS[@]}"

The array expansion produces one word per element of the array, so that the whitespace you quoted when the array was created is not treated as a word separator when constructing the list of arguments that are passed to test.sh.

Note that arrays are not supported by the POSIX shell, but this is the precise shortcoming in the POSIX shell that arrays were introduced to correct.

Sign up to request clarification or add additional context in comments.

1 Comment

For POSIX sh (and bash as well) you can do set -- -a "arg one" -b "arg two"; then use ./test.sh "$@" which will expand preserving the quoted argument boundaries.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.