It seems that bash
and zsh
will perform the variable and arithmetic expansions in a child process when
a) they're following a redirection operator like <
, >
, >>
or <<<
.
b) the command they're part of is not a built-in or function.
bash -c 'i=0; /bin/echo > $((i=7)).txt; echo $i'
0
zsh -c 'i=0; /bin/echo > $((i=7)).txt; echo $i'
0
ksh -c 'i=0; /bin/echo > $((i=7)).txt; echo $i'
7
ksh
above is like any other shell except bash
or zsh
.
This has nothing to do with those being arithmetic expansions: analogously, the same thing happens with
unset i; /bin/echo >${i:=7}.txt; echo $i
will only print 7
in shells other than bash
or zsh
.
However, as if this weren't bad enough, the behavior is not consistent in any fathomable way between bash
and zsh
:
bash -c 'i=0; command echo > $((i++)).txt; echo $i'
1
zsh -c 'i=0; command echo > $((i++)).txt; echo $i'
0
bash -c 'i=0; i=$i /usr/bin/printenv i > $((++i)).bash; echo $i; cat *.bash'
0
0
zsh -c 'i=0; i=$i /usr/bin/printenv i > $((++i)).zsh; echo $i; cat *.zsh'
0
1
So, my question is: What does the standard say? Is this acceptable?
I was able to find a lot about variable assignments as in KEY=val cmd
and when they may or may not "affect the current execution environment", but nothing about the interaction between redirections, $
-expansions and external commands.
And it could NOT be that it also applies to the variable assignments done as part of $
-expansions, because ls $((i=2+3))
results in i
being set to 5
in all the shells no matter if ls
is an external command or a built-in.
ksh
is that? ksh on macOS 10.14 (version sh (AT&T Research) 93u+ 2012-08-01) outputs0
for the first test.mksh
(the shell from android), the/bin/ksh
from OpenBSD,dash
, etc."$shell" -c 'i=0; echo "$((i+=1))" | "echo $((i+=1))"; echo "$i"'
. That was discussed not so long ago on the austin-group ml, but I don't remember the details.zsh
,command echo
runs theecho
command from the file system (unless insh
emulation) while inbash
it runs the builtinecho
(it would only bypass aecho
function).