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?
There are (at least) two ways to do this:
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[@]}"
is to ${array[*]}
what "$@"
is to $*
.
Or if you do not want to use arrays you need to use eval
:
bar() {
local args=()
for arg in "$@"
do
args="$args \"prefix $arg\""
done
eval foo $args
}
Here is a shorter version which does not require the use of a numeric index:
(example: building arguments to a find
command)
dir=$1
shift
for f in "$@" ; do
args+=(-iname "*$f*")
done
find "$dir" "${args[@]}"
Use arrays (one of the hidden features in Bash).
You can use the arrays just as you suggest, with a small detail changed. The line calling foo should read
foo "${args[@]}"
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