7

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

8
  • You'll want bi-dimensional arrays if you want to store several arguments (ksh93, not bash), or use some form of encoding (like printf %q output with eval). But sounds like an XY problem. Commented Jan 13, 2015 at 14:10
  • @StéphaneChazelas: Forgive my stupid question, but what is an "XY problem"? Commented Jan 13, 2015 at 14:13
  • mywiki.wooledge.org/XyProblem
    – jasonwryan
    Commented Jan 13, 2015 at 16:14
  • @jasonwryan: Thanks. I am writing a script to grade student submissions in a semi-automated way. For that, I need every program (task) of the submission to be executed with pre-defined parameters and to evaluate the results. Everything works fine so far, but I cannot use spaces in the path due to the issues described above, which is really annoying (my existing folder structure contains folder names with spaces). I am not quite sure whether the context I just provided helps solving the problem - avoiding the "XY problem", if I understood the explanation you linked to correctly. Commented Jan 13, 2015 at 16:55
  • @StéhaneChezales You can get something like 2d arrays in bash. If you do a separate array per 2cd dimension element and !nameref for each in an indexed array... hacky, and [indexing] doesnt work but sli:ci:ng does. But i agree that there is probably a better way to go about this. andreas: bash is not a db, you know. It's a command interpreter - and not even among the better ones - you really shouldnt be stacking so much state in its env like that. If your problem is your dir tree has spaces and shouldnt - maybe look to removing the spaces.
    – mikeserv
    Commented Jan 15, 2015 at 6:32

1 Answer 1

2

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
1
  • Nice - that seems to do the trick. Thank you. Commented Apr 27, 2015 at 7:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .