tags:

views:

873

answers:

4

I am having some issues with word-splitting in bash variable expansion. I want to be able to store an argument list in a variable and run it, but any quoted multiword arguments aren't evaluating how I expected them to.

I'll explain my problem with an example. Lets say I had a function decho that printed each positional parameter on it's own line:

#!/bin/bash -u
while [ $# -gt 0 ]; do
  echo $1
  shift
done

Ok, if I go decho a b "c d" I get:

[~]$ decho a b "c d"
a
b
c d

Which is what I expect and want. But on the other hand if I get the arguments list from a variable I get this:

[~]$ args='a b "c d"'
[~]$ decho $args
a
b
"c
d"

Which is not what I want. I can go:

[~]$ echo decho $args | bash
a
b
c d

But that seems a little clunky. Is there a better way to make the expansion of $args in decho $args be word-split the way I expected?

A: 

Have you tried:

for arg in "$@"
do
        echo "arg $i:$arg:"
        let "i+=1"
done

Should yield something like:

arg 1: a
arg 2: c d

in your case.

Straight from memory, no guarantee :-)

olli
This function performs exactly the same as decho. The problem is in calling decho, not decho itself.
David Dean
A: 

You can use:

eval decho $args
mouviciel
A: 

hmmm.. eval decho $args works too:

[~]$ eval decho $args
a
b
c d

And I may be able to do something with bash arrays using "${array[@]}" (which works like "$@"), but then I would have to write code to load the array, which would be a pain.

David Dean
A: 

You can move the eval inside the script:

#!/bin/bash -u
eval set -- $*
for i; 
do 
  echo $i;
done

Now you can do:

$ args='a b "c d"'
$ decho $args
a
b
c d

but you'll have to quote the arguments if you pass them on the CL:

$ decho 'a b "c d"'
a
b
c d
Dennis Williamson