Variable assignments specified with eval shell built-in

According to the POSIX specifications eval is a special shell built-in, which should imply that variable assignments specified together with it should remain in effect after the built-in completes. Thus one would expect IFS to be changed after this:

var=$'a\nb c'
$ IFS=$'\n' eval '
for i in $var; do
  echo "$i"
done'
a
b c

But it isn't:

$ set | grep ^IFS
IFS=$' \t\n'

Hi.

For this script:

#!/bin/bash --posix
#!/usr/bin/env dash
#!/usr/bin/env bash

# @(#) s1	Demonstrate IFS setting.

# Section 1, setup, pre-solution.
# Infrastructure details, environment, commands for forum posts. 
# Uncomment export command to test script as external user.
# export PATH="/usr/local/bin:/usr/bin:/bin"
set +o nounset
pe() { for i;do printf "%s" "$i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
# C=$HOME/bin/context && [ -f $C ] && . $C eval
version 2>&1 >/dev/null && version =o eval
set -o nounset
pe " posix setting: \"$(set -o | grep -i posix)\""
pe

# Section 2, solution.
pl " Results:"
pe " original: IFS is $(set | grep ^IFS | od -bc)"
var=$'a\nb c'
IFS=$'\n' eval '
pe " before loop: IFS is $(set | grep ^IFS | od -bc)"
for i in $var; do
  echo "$i"
done
'
pe " after loop:  IFS is $(set | grep ^IFS | od -bc)"

exit 0

The setting stays the same:

% ./s1
OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
Distribution        : Debian GNU/Linux 5.0 (lenny) 
eval - is a shell builtin [bash]
 posix setting: "posix          	on"


-----
 Results:
 original: IFS is 0000000 111 106 123 075 047 040 011 012
          I   F   S   =   '      \t  \n
0000010
 before loop: IFS is 0000000 111 106 123 075 047 012
          I   F   S   =   '  \n
0000006
a
b c
 after loop:  IFS is 0000000 111 106 123 075 047 012
          I   F   S   =   '  \n
0000006

I think this is what you expected.

The dash and plain bash did not keep the before-loop setting ... cheers, drl

1 Like

and for ksh93

 original: IFS is 0000000  111 106 123 075 044 047 040 134 164 134 156 047 012
           I   F   S   =   $   '       \   t   \   n   '
0000015
 before loop: IFS is 0000000  111 106 123 075 044 047 134 156 047 012
           I   F   S   =   $   '   \   n   '
0000012
a
b c
 after loop:  IFS is 0000000  111 106 123 075 044 047 134 156 047 012
           I   F   S   =   $   '   \   n   '
1 Like

Thanks guys.. Mystery solved! I ran it through ksh and dash before but I must have been looking at the wrong thing .... It is a bash-only thing then. I never realized default bash is so much different from POSIX and that you really need to use --posix for it to be compliant (at least the way it is compiled in my distribution)

That'll be item #23 on this list...
Bash POSIX Mode - Bash Reference Manual

Note that Bash even in POSIX mode is not fully POSIX compliant. It is mostly compliant. There are weasel words used to avoid claiming full compliance.

Chet R has no interest in full conformance.