Question

Can someone explain what's going on here. All of this is executed consecutively in the same shell.

$ array=(a b c)
$ echo "${array[*]}"
a b c

So far so good.

$ IFS=/ echo "${array[*]}"
a b c

That's ok, the expansion happened before the whole line got executed.

$ IFS=/ x="${array[*]}"
$ echo $x
a b c

Same here, the expansion happened first, and x got that value.

$ echo "${array[*]}"
a/b/c

But ${array[*]} got changed, and the change is permanent.

$ x="${array[*]}"
$ echo $x
a b c

Ok, this is normal, I think - the original, default IFS value was used to expand the array variable in this assignment.

$ echo "${array[*]}"
a/b/c
$ 

But this totally doesn't make sense to me. First, the default IFS is not used here. Second, the assignment x="${array[*]}" didn't affect the value of ${array[*]} the same way it did before, in IFS=/ x="${array[*]}".

Was it helpful?

Solution

When you use:

IFS=/ echo "${array[*]}"

Then IFS is set local to the echo command (although not used by echo)

When you use:

IFS=/ x="${array[*]}"

Then these are two separated variable assignment, one for IFS and one for x, so the IFS is now permanently changed to / as @jaypal mentioned.

When you use:

$ echo "${array[*]}"

Then - when quoted - the first character of IFS is used as an output field separator with expansion of the array

If it is unquoted, then it produces space separated fields:

$ echo ${array[*]}

Also, when you would use:

$ echo "${array[@]}"

Then each array element is expanded to a separate word, so the output field separator is not used so it becomes a single space..

OTHER TIPS

First, some really simple cases to explain where the confusion is coming from. I'll use proper quoting, although it is not requred here, since we'll be operating with single character strings.

Case A: an assignment followed by a command.

$ x=y echo "$x"

$ echo "$x"

$ 

Two things are happening here:

  • When followed by a command, an assignment is local to that command only. That's why the second echo "$x" returns an empty string.
  • Parameter expansion happens first, before the assignment is carried out. That's why the first echo "$x" returns an empty string as well. Effectively, x=y does absolutely nothing in this case.

Case B: Two assignments on the same line.

$ x=y z="$x"
$ echo "$x"
y
$ echo "$z"
y
$ 

The same two points are now opposite:

  • Both assignments are effective for the rest of the shell (or until unset).
  • Parameter expansion is not happening right away. The first assignment is carried out, and the result is used in the second assignment. Hence, both x and z are set to y for the rest of the shell.

Arrays, IFS and quoting.

These all played part as well, for sure, and worth explaining to someone who is not familiar with them. However, for me the issue was mainly about the assignments, and once that was clarified, everything else fell into place. Note that the value of IFS is applied to unquoted $IFS itself. So echo $IFS will always return an empty line:

$ IFS=BOO
$ echo $IFS

$ 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top