Rad*_*anu 12 bash command-line
在bash中,当我运行以下命令时:
sh -c "command"是否创建了一个子shell然后command执行?
我的猜测是命令将在当前的shell中运行,但我不确定.这个猜测来自我已经使用以下命令测试的事实:
echo $BASHPID, $BASH_SUBSHELL
和
sh -c "echo $BASHPID, $BASH_SUBSHELL"
结果是一样的.但是,有人告诉我这可能有点误导,因为在执行命令之前可能会替换变量.这是真的吗?
我会说不.
子shell通常保留给shell进程需要在隔离环境中执行操作的任何实例,但是可以访问shell的当前状态(的副本),包括所有全局和局部变量.
例子:
echo x | read yline=$( read < file && echo "$REPLY" )在大多数情况下,这会导致shell进程自行分叉.
在ksh93的最新更新中,一些子shell实际上可能不会分叉新进程.
问题的关键在于子shell始终是隐式创建的.
Running sh -c ...将创建一个新的 shell进程,它将丢弃大部分状态并从头开始.这意味着普通(本地,全局)shell变量消失了.当然,新shell将包含所有导出变量的副本.
对问题的不同解释可能是该-c选项是否为运行分配了一个新进程...?  答:没有.它没有.但是,传递给-c参数的某些命令可能需要shell生成子shell,就像它们是脚本的一部分或交互式键入一样.
我认为通过示例可以了解情况
(在我的情况下sh是一个符号链接/bin/dash).
我做了这个测试sh:
echo $$ ; sh -c 'echo $$ ; sh -c '"'"'echo $$'"'"' '
16102
7569
7570
三种不同PID,三种不同shell.(如果有不同的shell,则没有子shell生成).
以类似的方式 BASH
echo $$ $BASHPID, $BASH_SUBSHELL ; bash -c 'echo $$  $BASHPID $BASH_SUBSHELL  ; bash -c '"'"'echo  $$ $BASHPID $BASH_SUBSHELL '"'"' '
16102 16102, 0
10337 10337 0
10338 10338 0
三种不同$BASHPID没有区别$BASH_SUBSHELL(请参阅下面的注释,了解$$和之间的差异$BASHPID).
如果我们是在一个子shell不需要重新初始化,然后$$和$BASHPID应有所不同.
以同样的方式$BASH_SUBSHELL不增加,它总是如此0.因此有2条线索再次说明没有新的子壳生成,我们只有新的炮弹.
从man bash(4.2.45(1)-release)我汇报一下一些相关部件时,子shell是催生:   
管道中的每个命令都作为单独的进程执行(即,在子shell中).
如果命令由控制操作符&终止,则shell 在子shell中在后台执行命令. shell不等待命令完成,返回状态为0.
由a分隔的命令; 按顺序执行; shell等待每个命令依次终止.返回状态是最后执行的命令的退出状态....
( list )     列表在子shell环境中执行
 {list; } list只是在当前的shell环境中执行.
甲协进程是由前面外壳命令coproc保留字.协处理在子shell中异步执行...
$扩展为shell的进程ID .在()子shell中,它扩展为当前shell的进程ID ,而不是子shell.
备注:
BASHPID扩展为当前bash进程的进程ID.这与$$ 
某些情况不同,例如不需要重新初始化bash的子shell.    BASH_SUBSHELL每次生成子shell或子shell环境时增加1.初始值为0.  
对于使用单引号''和双引号之间的差异,"" 您可以看到这个问题.让我们只记得,如果你在双引号中编写命令,""那么变量将通过原始shell的参数扩展进行评估,如果启用了extquote,则默认情况下是shopt.(参见4.3.2 Bash参考手册中内置的商店)  
*extquote*如果设置,则$'string'和$"string"引用在用双引号括起来的$ {parameter}扩展中执行.默认情况下启用此选项.
如需进一步参考,您可能会发现有用的例
man bash.Shell Expansions所述的bash的手册.  我也检查过它,不,我不认为(-c)召唤一个子壳.如果我们引用sh它自己,则yes sh是一个被召唤的shell,但如果它是关于它sh自身内的子shell则不是.我们可以通过运行如下命令来验证这一点:
# bash -c 'pstree -p; echo Value of PPID in Callee: $PPID; echo Callee PID: $BASHPID / $$'; echo "Caller PID: $$"
bash(28860)???bash(17091)???pstree(17092)
Value of PPID in Callee: 28860
Callee PID: 17091 / 17091
Caller PID: 28860
正如您所看到的那样,被调用的shell(17091)和调用者shell(28860)都直接作为子父级连接.他们之间什么都没有.$BASHPID并且$$甚至是相同的,在这种情况下如果你在子壳上应该是不同的.这只是告诉我在调用命令时没有调用子shell -c.
这只有一个特殊的行为,那就是召唤一个外部二进制文件,例如:
# bash -c 'pstree -p'; echo "Caller PID: $$"
bash(28860)???pstree(17124)
Caller PID: 28860
bash将自己从forking中解脱出来并决定直接执行exec()唯一的命令.您可能会认为,如果命令引用外部可执行二进制文件,或许bash总是对最后一个命令执行此操作,但是不会:
# bash -c 'echo Value of PPID in Callee: $PPID; echo Callee PID: $BASHPID / $$; pstree -p'; echo "Caller PID: $$"
Value of PPID in Callee: 28860
Callee PID: 17128 / 17128
bash(28860)???bash(17128)???pstree(17129)
Caller PID: 28860
现在约
echo $ BASHPID,$ BASH_SUBSHELL
和
sh -c"echo $ BASHPID,$ BASH_SUBSHELL"
结果是一样的.
它应该是相同的,如果echo $BASHPID, $BASH_SUBSHELL在同一个shell中执行,因为"echo $BASHPID, $BASH_SUBSHELL"首先由shell解释命令,然后将它作为参数传递给它sh.如果BASHPID让我们说28860和BASH_SUBSHELL0,那么扩展的值"echo $BASHPID, $BASH_SUBSHELL"就是'echo 28860, 0'命令实际上是这种情况sh -c 'echo 28860, 0'.实际上,这种方法的正确方法是使用单引号来仅允许在新的被调用shell的上下文中进行解释:sh -c 'echo $BASHPID, $BASH_SUBSHELL'虽然我不确定命令本身是否有助于测试.
所以基本上我所说的是,如果召唤一个子壳,那么测试echo $BASHPID, $BASH_SUBSHELL+ sh -c "echo $BASHPID, $BASH_SUBSHELL"没有证明任何东西-c,并且那个告诉你它可能误导的人因为变量可能被替换是正确的.
尽管如此,我自己的测试表明,Bash确实没有用它来召唤一个子shell(-c).
| 归档时间: | 
 | 
| 查看次数: | 12142 次 | 
| 最近记录: |