I'm trying to substitute a string variable, containing multiple quoted words, as a parameter to a command.
Thus, given the following example script (Note the -x in the shebang, which causes the output to be logged to stderr),
#!/bin/bash -x
myArg="\"hello\" \"world\""
echo "string is:" $myArg
exit
Which gives us,
+ myArg='"hello" "world"'
+ echo 'string is:' '"hello"' '"world"'
string is: "hello" "world"
+ exit
Line two shows what is actually passed to the command; bash has added single quotes to each word in the string. If I instead, thusly, quote "$myArg", the same occurs but for the whole string rather than each word.
Now, imagine that instead of echo
, we are passing the string to a program where some of the arguments need to be quoted patterns, such as "*"
(which mustn't be expanded by the shell).
To clarify, I don't want the single quotes added at all during the expansion. How might I achieve this?
Don't use quotes, use an array (see BashFAQ #050):
If it really needs to be in the form of quoted strings within a string, you're either going to have to use something like
eval "echo $myArg"
(which can cause some really nasty bugs, if you aren't careful) or parse it yourself (which is going to be difficult).There is a portable way to split expand a variable but keep spaces. Bash arrays are not needed. Dash (Ubuntu's /bin/sh) would work too.
Use some character to separate arguments that is definitely not used inside the arguments. The below example uses semicolon, but it could be a newline or another character. Change the
IFS
variable to a newline temporarily when the list of arguments is expanded. RestoreIFS
to the original value as soon as possible, even if it means doing it in the loop. If the loop is not guaranteed to run at least once, do it after the loop as well.Note that every expanded argument is printed individually.
If you want to pass a variable value as a parameter (99% of cases on SO), simply use proper quoting:
If you want to pass several arguments, use arrays:
I don't think it is doing what you think it is doing.
I see no extra quotes of any kind-
echo
gets three argument strings.Bash will expand the variable first, so
becomes (though without the literal backslashes- this is why string escaping is a PITA)
And the args array is:
Now, if you add the
*
, or glob path expansion in one of those, Bash will at this point expand it, unless you escape it, or use single quotes in your literal command.