views:

251

answers:

4

In bash one can escape arguments that contain whitespace.

foo "a string"

This also works for arguments to a command or function:

bar() {
    foo "$@"
}

bar "a string"

So far so good, but what if I want to manipulate the arguments before calling foo?

This does not work:

bar() {
    for arg in "$@"
    do
        args="$args \"prefix $arg\""
    done

    # Everything looks good ...
    echo $args

    # ... but it isn't.
    foo $args

    # foo "$args" would just be silly
}

bar a b c

So how do you build argument lists when the arguments contain whitespace?

+2  A: 

Use arrays (one of the hidden features in Bash).

JesperE
how exactly? I have updated my question with an attempt to use an array - which didn't work.
tarsius
There does not seem to be an easy way to pass arrays to functions (which really are subshells). You'd need to quote them and pass them as regular argument (as you would to any other command).
JesperE
+3  A: 

There are (at least) two ways to do this:

(1.) Use an array and expand it using "${array[@]}":

bar() {
    local i=0 args=()
    for arg in "$@"
    do
        args[$i]="prefix $arg"
        ((++i))
    done

    foo "${args[@]}"
}

So what have we learned? "${array[@]}" it to ${array[*]} what "$@" it to $*.

(2.) Or if you do not want to use arrays you need to use eval:

bar() {
    for arg in "$@"
    do
        args="$args \"prefix $arg\""
    done

    eval foo $args
}
tarsius
damn, should have gotten here earlier -- could have spared you the work :)
hop
A: 

You can use the arrays just as you suggest, with a small detail changed. The line calling foo should read

 foo "${args[@]}"
jpalecek
A: 

I had a problem with this too as well. I was writing a bash script to backup the important files on my windows computer (cygwin). I tried the array approach too, and still had some issues. Not sure exactly how I fixed it, but here's the parts of my code that are important in case it will help you.

WORK="d:\Work Documents\*"
#   prompt and 7zip each file
for x in $SVN $WEB1 $WEB2 "$WORK" $GRAPHICS $W_SQL
do
    echo "Add $x to archive? (y/n)"
    read DO
    if [ "$DO" == "y" ]; then
     echo "compressing $x"
     7zip a $W_OUTPUT "$x"
    fi
    echo ""
done
tj111