在以下情况下,bash和zsh将在子进程中执行变量和算术扩展
( a)他们跟踪的是一个重定向操作符,如<、>、>>或<<<。
( b)他们参与的命令不是内置的或函数。
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和除bash或zsh之外的任何其他shell一样。
这与那些算术展开无关:类似地,同样的事情也发生在
unset i; /bin/echo >${i:=7}.txt; echo $i将只在bash或zsh以外的shell中打印D13。
然而,就好像这还不够糟糕一样,bash和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所以,我的问题是:What标准中说吗?这可以接受吗?
我能够找到很多关于变量赋值的信息,比如在KEY=val cmd中,以及它们是否“影响到当前的执行环境”,但是对于重定向、$-expansions和外部命令之间的交互却没有发现。
它不可能也适用于作为$-expansions的一部分完成的变量赋值,因为ls $((i=2+3))会导致在所有shell中将i设置为5,而不管ls是外部命令还是内置的。
发布于 2019-05-17 18:41:01
这是未指定的,因此每个shell都可以做它想做的事情,而不必记录细节。(从历史的角度来看,之所以没有具体说明,是因为不同的shell所做的事情不同。)从技术上讲,贝壳可以抛硬币。在实践中,在单独的环境中运行的内容和不运行的细节可能取决于在某些情况下所做的优化,例如,取决于命令是否是内置的,取决于重定向是否指向/从/dev/null,取决于陷阱是否活动,取决于set -e是否有效,取决于命令是否是列表中的最后一个命令,等等。
来自SUSv4 (POSIX.1-2008年) “壳牌和实用程序”-§2.9.1“简单命令”:
如果命令名不是一个特殊的内置实用程序或函数,则变量赋值应导出到命令的执行环境,并且除作为步骤4中执行的扩展的副作用外,不影响当前的执行环境。在这种情况下,未指定:
为了澄清:“步骤4”包括参数展开(例如${i:=7})和算术展开(例如$((i=7)))。“不影响当前执行环境”的变量扩展是命令前面的变量,例如i=7 ls。因此,这一段除其他外说,如果参数展开或变量展开修改了变量的值,那么在命令返回后,这是否会产生影响,这是一个未知数。
在实践中,shell通常通过先分叉,然后在子shell中重定向,将重定向应用于外部命令。但是,在创建子subshell之前还是之后,它们在确定重定向的目标时有所不同。
https://unix.stackexchange.com/questions/519398
复制相似问题