Bash – Escaping strings in associative arrays (bash)

bashescape-charactersstring

I am writing a script which executes a number of programs with arguments. To simplify it as much as possible, consider the following example:

programs=( "ls" "echo" )
declare -A parameters
parameters["ls"]="-l /tmp/foo"
parameters["echo"]="Hello"

for program in "${programs[@]}"
do
  $program ${parameters[$program]}
done

This works fine as long as there are no spaces in the arguments. Of course, escaping strings has been discussed before, so I tried all of the different ways I could find here on StackExchange and some other pages. However, I could not find a solution which works in my case which uses associative arrays. For example, when I want to get a listing of "/tmp/foo bar", neither this

parameters["ls"]="-l /tmp/foo bar"

nor this

parameters["ls"]="-l \"/tmp/foo bar\""

nor this

parameters["ls"]="-l /tmp/foo\ bar"

works as expected. Similarly, putting quotes around the program call in the loop

  $program "${parameters[$program]}"

does not work either, since the two parameters (-l and the path) are interpreted as one parameter.

I found the closest thing to a solution in this post which proposes using multiple separate variables, one for each argument, for the program call. This, however, is not possible in my use case which requires a variable number of arguments for each program – thus my use of the associative array.

Is there any other way to escape the path name?

Best regards
Andreas

Best Answer

First, create an array with the parameters.

Then, store the array string value (found with declare -p) at parameters, and recover and use it as an actual array later on like in:

#!/bin/bash

programs=( "ls" "echo" )
declare -A parameters

arrayTmp=("-l" "/tmp/foo bar")
parameters["ls"]="`declare -p arrayTmp |sed -r "s,[^=]*='(.*)'$,\1,"`"

parameters["echo"]="Hello"

for program in "${programs[@]}";do
    echo "PROGRAM: $program"
    declare -a arrayTmp="${parameters[$program]}"
    $program "${arrayTmp[@]}"
    arrayTmp=()
done
Related Question