12

I have the following function:

bar() { echo $1:$2; }

I am calling this function from another function, foo. foo itself is called as follows:

foo "This is" a test

I want to get the following output:

This is:a

That is, the arguments that bar receives should be the same tokens that I pass into foo.

How does foo need to be implemented in order to achieve this? I’ve tried the following two implementations, but neither works:

  • foo() { bar $*; }

    – output: this:is

  • foo() { bar "$*"; }

    – output: this is a test:

My question is effectively how I can preserve the quoting of arguments. Is this possible at all?

2 Answers2

17

Use "$@":

$ bar() { echo "$1:$2"; }
$ foo() { bar "$@"; }
$ foo "This is" a test
This is:a

"$@" and "$*" have special meanings:

  • "$@" expands to multiple words without performing expansions for the words (like "$1" "$2" ...).
  • "$*" joins positional parameters with the first character in IFS (or space if IFS is unset or nothing if IFS is empty).
Lri
  • 5,223
  • Thanks, I wasn’t aware that $* had this semantic – now it’s logical. I think this answer actually solves another problem I’ve been having when iterating over arrays … – Konrad Rudolph Jun 06 '13 at 16:29
6

You must use $@, instead of $*

bar() { echo "$1:$2"; }

foo() { bar "$@"; }

foo "This is" a test

ouput

This is:a

Why does it work?

Because with $*, all parameter is seen as a single word, it mean that you will pass This is a test to bar function. In this case, the 1st parameter pass to function bar is This, 2nd is is.

With $@, each parameter is a quoted string, it mean that you will pass 'This is' 'a' 'test' to bar funtion. So the 1st parameter pass to function bar is This is, 2nd is a.

cuonglm
  • 153,898