6

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
  • 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 6:32
1

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
  • Nice - that seems to do the trick. Thank you. – Andreas Unterweger Apr 27 '15 at 7:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.