-2

First, a simple situation, echo "$@" directly in a for loop:

#!/bin/bash
set -- "First one" "second" "third:one" "" "Fifth: :one"
IFS=:

# IFS=":", using "$@"
c=0
for i in "$@"
do echo "$((c+=1)): [$i]"
done

Output, as expected:

1: [First one]
2: [second]
3: [third:one]
4: []
5: [Fifth: :one]

But when I assign "$@" to a variable var and then echo $var in a for loop, things become complicated:

#!/bin/bash
set -- "First one" "second" "third:one" "" "Fifth: :one"
IFS=:

# IFS=":", using $var (var="$@")
var="$@"
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done

It Print:

1: [First one second third]
2: [one  Fifth]
3: [ ]
4: [one]

Why output changed? Can anybody tell me what happened under the hood when I add var="$@" and then echo $var in a for loop?

Feng Yu
  • 359
  • 1
  • 4
  • 17

2 Answers2

2

from: What are the special dollar sign shell variables?

"$@" is an array-like construct of all positional parameters, {$1, $2, $3 ...}

Community
  • 1
  • 1
beoliver
  • 5,579
  • 5
  • 36
  • 72
1

Generally, when running a script, the arguments given on the command line (called positional parameters) are available within the script as "$1", "$2", etc... The list of positional parameters is contained in the special shell variable $@ (and also in $*). A special property of $@ is that when quoted (e.g. "$@") it will maintain the quoted relationship of the positional parameters. (e.g. if an argument is given as "First one", $@ maintains it as a single argument as opposed to two)

However, there is also a method for setting positional parameters from within the shell script using set -- var1 var2 var3, etc..

IFS is the Internal Field Separator that controls word-splitting. (that is how strings are split into words -- default: space tab newline) Changing IFS=: causes word-splitting to occur on the ':' character instead of the default.

So in your case you have new positional parameters "First one" "second" "third:one" "" "Fifth: :one" set and if you look at where they will break if split at each ':' character, you get:

"First one second third"
"one  Fifth"
"  "
"one"

Mystery solved. This is a good example to teach you about positional parameters and the Internal Field Separator along with its effect on word-splitting. Learn it - it is important is shell scripting.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • An important point is also that with `var="$@"`, you are left with a single string of white-space-separated words; there is no longer any distinction between the space that is part of each parameter and the space that separates two parameters. – chepner Dec 03 '15 at 12:32