Store quotes in variable to use as command line parameter Bash
The line in your code weka $1 ${search["$1"]}
is being subject to shell spliting.
If you have not changed the variable $IFS
that splitting will happen on spacetabnew line.
The line gets expanded to:
weka $1 ${search["$1"]}
weka a -search "a params" -search "other a params"
But getting split as described above, this is what it means:
<weka> <a> <-search> <"a> <params"> <-search> <"other> <a> <params">
You can see exactly the same prepending printf to the line:
$ printf '<%s> ' weka $1 ${search["$1"]}; echo
<weka> <a> <-search> <"a> <params"> <-search> <"other> <a> <params">
This will get better if the variables are correctly quoted:
$ printf '<%s> ' weka "$1" "${search["$1"]}"; echo
<weka> <a> <-search "a params" -search "other a params">
But that is not what you want. You need to split it, but not on simple spaces.
What to do?
There are two solutions:
Split manually
Use some character like #
to manually mark the split position:
search=( ["a"]='-search#a params#-search#other a params' ["b"]='-search#just these params' )
And then tell bash which is the character you used to split with IFS
, so it could split the string in a new array b
:
IFS='#'
b=( ${search["a"]} )
printf '<%s> ' "${b[@]}"; echo
Which produces:
<-search> <a params> <-search> <other a params>
The exact splitting you want.
The only problem is that IFS
got changed, but we can solve that in a function making IFS
local:
callsplit(){
local IFS='#'
b=( ${search["$1"]} )
weka "$1" "${b[@]}"
}
Use Eval
The other solution is to use eval to re-parse the command line so the shell could split it as is the common way of shells to split lines.
The value of the variable search will be as you defined it:
search=( ["a"]='-search "a params" -search "other a params"'
["b"]='-search "just these params"' )
But we will expand the execute line with eval:
eval weka "$1" "${search["$1"]}"
If you want to see how is the line expanded, use this:
$ eval printf "'<%s> '" weka "$1" "${search["$1"]}"; echo
<weka> <a> <-search> <a params> <-search> <other a params>
The whole script will be:
#!/bin/bash
declare -A search
search+=( ["a"]='-search "a params" -search "other a params"')
search+=( ["b"]='-search "just these params"' )
call_thing() {
eval weka "$1" "${search["$1"]}"
} # <-- closing brace for the function
call_thing "a"
Note: That will work correctly assuming that the values of search are set inside the script (no external attacker could set them) and those values are quoted as a common shell "command line" is quoted.
Warning: The use of eval may allow data as an string to be converted into code like a command. In this specific script, this line:
call_thing "a; touch new_file"
Will execute the command touch new_file
. But any other command could also be executed. Be careful, very careful with what you feed to eval
.
Having said the above, remember that there are many dangerous commands that could be executed in shell, like rm -r /
. The command eval
is not more powerful than any of those. Just be careful.