Yes, the behavior is different. The whole description is not so simple.
First: when is it equal?
This code line :
$ var=1; printf "%s" "$var"; var=2 export var; echo " $var"
Will print 1 2
in all (non-csh like) shells except zsh.
jsh : 1 2 # ATT version sh (heirloom).
ash : 1 2
yash : 1 2
dash : 1 2
zsh/sh : 1 2
bash : 1 2
posixbash : 1 2
lksh : 1 2
mksh : 1 2
ksh93 : 1 2
attsh : 1 2
zsh : 1 1
That looks like a mistake of zsh to me. How could be reasonable that exporting a variable does not retain the exported value ?
But that is because the exported variable: var
, is the same var that is printed.
Exporting some other var.
If the line is changed to something more similar to what you are asking, with some other varname, like this:
$ var=1; printf "%s" "$var"; var=2 export othervar; echo " $var"
The difference(s) become clear:
jsh : 1 2
dash : 1 2
bash : 1 1
posixbash : 1 2
ksh93 : 1 2
zsh : 1 1
It is clear that bash is different to old sh (Bourne), newer sh (dash), ksh and others (not listed here).
But what is more important is that bash acts differently than bash --posix
.
Posix requirement.
Some of the shell builtins (not all) are called "special built-ins":
From: 2.14. Special Built-In Utilities
The following "special built-in" utilities shall be supported in the shell command language.
… however, the special built-in utilities described here differ from regular built-in utilities in two respects:
An error in a special built-in utility may cause a shell executing that utility to abort, while an error in a regular built-in utility shall not cause a shell executing that utility to abort. …
As described in Simple Commands, variable assignments preceding the invocation of a special built-in utility remain in effect after the built-in completes; this shall not be the case with a regular built-in or other utility.
So, in a simple command: var=2 specialBuiltin
the variable var
should retain its value after the specialBuiltin has exited. But not all shell implementations follow such rule.
So, this should print 1 hello 2
(as eval
is an special builtin):
var=1; printf '%s ' "$var"; var=2 eval printf %s hello; echo " $var"
It does in sh
and bash --posix
but not in plain bash.
List of special builtins.
In fact, The POSIX list of special builtins is here, the list being:
02 break
03 :
04 .
05 continue
06 eval
07 exec
08 exit
09 export
10 readonly
11 return
12 set
13 shift
14 times
15 trap
16 unset
The number in first column is the value of var used for each test.
We could test all special builtins (except exit, exec and times) with this code:
var=01;
while : ; do var=02 break; done; printf ' %s' "02-$var"; var=01
var=03 : ; printf ' %s' "03-$var"; var=01
echo 'printf " %s" "04-<$var>"' >source-sh
var=04 . source-sh; printf ' %s' "04-$var"; var=01
c=0; while ((c++<1)); do
var=05 continue
done; printf ' %s' "05-$var"; var=01
var=06 eval 'printf " %s" "06-<$var>"'; printf ' %s' "06-$var"; var=01
#( var=07 exec bash -c 'printf " %s" "07-$var"'); var=01
#( var=08 exit; printf ' %s' "08-$var" ); var=01
var=09 export var; printf ' %s' "09-$var"; var=01
var=10 readonly i; printf ' %s' "10-$var"; var=01
varfun(){ var=11 return; }; varfun; printf ' %s' "11-$var"; var=01
var=12 set -- aa ; printf ' %s' "12-$var"; var=01
var=13 shift; printf ' %s' "13-$var"; var=01
var=15 trap; printf ' %s' "14-$var"; var=01
var=16 unset j; printf ' %s' "15-$var"; var=01
echo
To print this list:
jsh : 02-02 03-03 04-<04> 04-04 05-05 06-<06> 06-06 09-09 10-10 11-11 12-12 13-13 15-15 16-16
dash : 02-02 03-03 04-<04> 04-04 05-05 06-<06> 06-06 09-09 10-10 11-11 12-12 13-13 15-15 16-16
bash : 02-01 03-01 04-<04> 04-01 05-01 06-<06> 06-01 09-09 10-01 11-01 12-01 13-01 15-01 16-01
posixbash : 02-02 03-03 04-<04> 04-04 05-05 06-<06> 06-06 09-09 10-10 11-11 12-12 13-13 15-15 16-16
ksh93 : 02-02 03-03 04-<04> 04-04 05-05 06-<06> 06-06 09-09 10-10 11-11 12-12 13-13 15-15 16-16
zsh : 02-01 03-01 04-<04> 04-01 05-01 06-<06> 06-01 09-01 10-01 11-01 12-01 13-01 15-01 16-01
As you can see, where posix request that var retain 02
most shells retain it and print 02-02
, but not in bash (nor zsh) as they print 02-01
. Only in export
is bash printing 09-09
and zsh printing 09-01
.