I recently learnt“在大多数shell中,管道的每个命令都在一个单独的SubShell中执行”.但是,在这种情况下,两个命令都在同一个子shell中执行.
为什么会这样?有没有办法让这个工作?
完整示例:
$v=1 $v=5 echo "$v" 1 # I expected 5!
2.10.2,Shell语法规则
从规则7(b)开始,涵盖分配在简单命令之前的情况:
If all the characters preceding ‘=’ form a valid name (see the Base Definitions volume of IEEE Std 1003.1-2001,Section 3.230,Name),the token ASSIGNMENT_WORD shall be returned. (Quoted characters cannot participate in forming a valid name.)
[…]
Assignment to the NAME shall occur as specified in Simple Commands.
因此,对于符合POSIX的shell,需要解析此分配.
2.9.1,简单命令
Redirections shall be performed as described in Redirection.
Each variable assignment shall be expanded for tilde expansion,parameter expansion,command substitution,arithmetic expansion,and quote removal prior to assigning the value.
[…]
If no command name results,variable assignments shall affect the current execution environment. Otherwise,the variable assignments shall be exported for the execution environment of the command and shall not affect the current execution environment (except for special built-ins). If any of the variable assignments attempt to assign a value to a read-only variable,a variable assignment error shall occur. See Consequences of Shell Errors for the consequences of these errors.
因此:必须导出在简单命令的前缀的一部分中给出的赋值,并且不得影响“当前shell环境”,除非被调用的shell是特殊的内置函数.而且,这些步骤应遵循重定向,这些重定向本质上必须在命令调用过程的后期发生.
2.12,Shell执行环境
Utilities other than the special built-ins (see Special Built-In Utilities) shall be invoked in a separate environment that consists of the following. The initial value of these objects shall be the same as that for the parent shell,except as noted below.
[…]
Variables with the export attribute,along with those explicitly exported for the duration of the command, shall be passed to the utility environment variables
因此:这些变量在fork之后和执行命令被调用之前由子shell扩展,并且必须 – 通过规范 – 仅影响子环境.
现在,对于一些不同的行为:
v=5 sh -c 'echo "$v"'
…受益于sh实例在启动时从其环境变量(如POSIX规范的2.5.3节中的要求)创建shell变量.
顺便提一下,值得注意的是,您要求的语法是在简单命令中进行赋值,而不是在子shell中进行赋值.您可以控制管道中涉及的子shell中的赋值,如下所示:
{ v=5; echo "$v"; } | somecommand ...
…将赋值放入运行管道的第一个组件的子shell中(如果你的shell确实在子shell中运行该组件,这是未定义的行为,因为POSIX是关注的;来自规范:“作为扩展,但是,管道中的任何或所有命令可以在当前环境中执行“).