I am writing a script to call a command (weka, if you are curious) a couple of times with some different parameters.  One of the parameters, '-search < stuff > ' needs to be quoted.  In some cases I need to use multiple of these parameters eg.weka a -search a params -search other a paramsweka b -search just these params`I've been trying to use an associative array that looks something like:search=( [a]='-search a params -search other a params'[b]='-search just these params'Then make the call like:function call_thing_with_the_right_parameters_so_it_works_out_alright {    weka $1 ${search[$1]}} # <-- closing brace for the functioncall_thing_with_the_right_parameters_so_it_works_out_alrightAlas, no matter what I try, the quoting gets all buggered up:bash -x ./this_is_the_name_of_my_script_sorry_its_so_long...+ weka a -search 'a' 'params' # <-- (not what I want)...Any ideas?
Store quotes in variable to use as command line parameter Bash
bash;quoting
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 paramsBut 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 manuallyUse 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[@]}; echoWhich 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 EvalThe 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/bashdeclare -A searchsearch+=( [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 functioncall_thing aNote: 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_fileWill 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.