4

myFun1 and myFun2 below don't produce the same output. Why?

#!/bin/bash

myFun1() {
  local item
  IFS=:
  for item in "${@}"; do
    echo "->${item}<-"
  done
}

myFun2() {
  local items="${@}";
  local item
  IFS=:
  for item in "${items}"; do
    echo "->${item}<-"
  done
}

Invoking

myFun1 "a=b" "c='d 1'" "e"

produces

->a=b<-
->c='d 1'<-
->e<-

whereas

myFun2 "a=b" "c='d 1'" "e"

produces

->a=b c='d 1' e<-
  • 1
    Related - [What is the difference between $* and $@?](https://unix.stackexchange.com/q/41571/100397) – roaima Aug 18 '21 at 16:31
  • 2
    Does this answer your question? [What is the difference between $\* and $@?](https://unix.stackexchange.com/questions/41571/what-is-the-difference-between-and) – AdminBee Aug 25 '21 at 13:54

1 Answers1

5

This behavior is defined by POSIX, which both Bash and Zsh make an effort to adhere to.

@
Expands to the positional parameters, starting from one. When the expansion occurs within double-quotes, and where field splitting (see Field Splitting) is performed, each positional parameter shall expand as a separate field, ...

However, this behavior only applies to $@ itself. Assigning its value to another variable causes the meaning of the individual fields to be lost, and it's then treated as a single string (just as if you used $*).

I'm not certain about Zsh, but if in Bash you want to save $@ to another variable and be able to take advantage of field separation, you need to use an array.

myFun2() {
  local -a items=("${@}");
  local item
  IFS=:
  for item in "${items[@]}"; do
    echo "->${item}<-"
  done
}

In Bash, array expansion of the form "${array[@]}" has the same behavior as "$@".

James Sneeringer
  • 2,512
  • 13
  • 14