Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux Bash';吞咽';执行单个命令时的子shell子进程_Linux_Bash_Shell_Subshell - Fatal编程技术网

Linux Bash';吞咽';执行单个命令时的子shell子进程

Linux Bash';吞咽';执行单个命令时的子shell子进程,linux,bash,shell,subshell,Linux,Bash,Shell,Subshell,遇到了一个意想不到的bash/sh行为,我想知道是否有人能解释它背后的原理,并为下面的问题提供解决方案 在交互式bashshell会话中,我执行: $bash-c“睡眠10&&echo” 对于Linux上的ps,它看起来是这样的: \\uuuz-bash \_bash-c sleep 10&&echo \_睡眠10 流程树是我所期望的: 我的交互式bash shell进程($) 子shell进程(bash-c…) 儿童睡眠过程 但是,如果我的bash-c的命令部分是单个命令,例如: $bas

遇到了一个意想不到的
bash
/
sh
行为,我想知道是否有人能解释它背后的原理,并为下面的问题提供解决方案

在交互式
bash
shell会话中,我执行:

$bash-c“睡眠10&&echo”

对于Linux上的
ps
,它看起来是这样的:

\\uuuz-bash
\_bash-c sleep 10&&echo
\_睡眠10

流程树是我所期望的:

  • 我的交互式bash shell进程(
    $
  • 子shell进程(
    bash-c…
  • 儿童睡眠过程
但是,如果我的
bash-c
的命令部分是单个命令,例如:

$bash-c“睡眠10”

然后吞下中间的子shell,我的交互式终端会话在子进程中“直接”执行sleep。 流程树如下所示:

\\uuuz-bash
\_睡眠10

因此,从流程树的角度来看,这两种方法产生相同的结果:

  • $bash-c“睡眠10”
  • $sleep 10
这是怎么回事

现在我的问题是:有没有一种方法可以强制中间shell,而不管传递给
bash-c…
的表达式有多复杂

(我可以在我的实际命令中添加类似于
;echo;
的内容,并且“起作用”,但我宁愿不这样做。有没有更合适的方法来强制中间过程的存在?)


(编辑:在
ps
输出中键入;删除注释中建议的
sh
标记;再键入一次)

实际上有一条注释描述了此功能的基本原理:

/*如果这是一个简单的命令,请告诉execute\u disk\u命令
可能不需要分叉就可以脱身,只需执行即可。
这意味着像(睡眠10)这样的事情只会导致一个分叉。
但是,如果我们对命令计时或反转其返回值,
我们不能进行这种优化*/
if((user|u subshell | user|coproc)&&(tcom->type==cm|u simple | tcom->type==cm|u subshell)&&
((tcom->标志和命令时间管道)==0)&&
((tcom->标志和命令反转返回)=0))
{
tcom->flags |=CMD_NO_FORK;
如果(tcom->类型==cm\U简单)
tcom->value.Simple->flags |=CMD_NO_FORK;
}
bash-c'…'
案例中,当由In
内置/evalstring.c
确定时,设置
CMD\u NO\u FORK
标志

让shell这样做总是对您有利。只有在以下情况下才会发生:

  • 输入来自硬编码字符串,shell位于该字符串中的最后一个命令
  • 命令完成后,将不再运行其他命令、陷阱、挂钩等
  • 退出状态不需要反转或修改
  • 无需退出重定向
这样可以节省内存,使进程的启动时间稍快一些(因为它不需要设置
fork
ed),并确保发送到PID的信号直接发送到正在运行的进程,从而使
sh-c“sleep 10”
的父进程能够准确地确定哪个信号被杀死
sleep
,如果它真的被信号杀死了

但是,如果出于某种原因想要抑制它,您只需要设置一个陷阱——任何陷阱都可以:

# run the noop command (:) at exit
bash -c 'trap : EXIT; sleep 10'

如果可能的话,为什么不希望进行这种优化?在用户可以传递任意命令的环境中,在处理子进程时,主要确保行为一致。我不确定绕过这个优化是否是我的解决方案(我面临的实际问题必须处理sudo:的变化)。但这种行为很有趣,我想了解更多。问得好。你的意思是在你第一个ps树的第2行说
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\&echo
而不是
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\。因此类似于
bash-c:;sleep 10“
即使在启动睡眠后仍能保持shell运行。@ilkkachu,我的直觉预期是,这可能会因版本而异--3.2将在2014年底实现
应禁止fork
,f/e之前。即使是今天的情况,我也不希望在未来的版本中仍然如此(这有望解决丢失的优化机会)——而陷阱总是需要保持shell运行。在3.2和4.4.nod中的行为似乎类似。了解当前的行为很有用,但我仍然怀疑它是否值得信赖。如果在脚本的最后一个命令中使用隐式的
exec
,可以让脚本运行得更快(当然,在典型情况下只有几毫秒,但仍然如此),那么如果有人编写它,Chet为什么会拒绝该补丁呢?谢谢。如果您想知道为什么我要强制中间shell在所有情况下都存在,那么答案与这里提到的
sudo
中的更改有关:。对sudo的kill过去被转发给它的子进程,但现在已经不是这样了,所以我尝试在不同的进程组中生成我的进程。