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

  • 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. – Stéphane Chazelas Jan 13 '15 at 14:10
  • @StéphaneChazelas: Forgive my stupid question, but what is an "XY problem"? – Andreas Unterweger Jan 13 '15 at 14:13
  • http://mywiki.wooledge.org/XyProblem – jasonwryan Jan 13 '15 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. – Andreas Unterweger Jan 13 '15 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 Jan 15 '15 at 06:32
  • @mikeserv: Yes, I already worked around by renaming my folders, but I thought that I am just missing something in the documentation or while searching on how to escape properly. – Andreas Unterweger Jan 15 '15 at 09:45
  • @AndreasUnterweger - probably not. Its not easy to do - and probably not worth doing. Pretty messy overall – mikeserv Jan 15 '15 at 09:47
  • @mikeserv it was actually fun to do :) – Aquarius Power Apr 27 '15 at 01:28

1 Answers1

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