繁体   English   中英

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

[英]Bash 'swallowing' sub-shell children process when executing a single command

陷入意想不到的bash / sh行为,我想知道有人可以解释它背后的基本原理,并为下面的问题提供解决方案。

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

$ bash -c 'sleep 10 && echo'

使用Linux上的ps ,它看起来像这样:

\\_ -bash \\_ bash -c sleep 10 && echo \\_ sleep 10

进程树是我所期望的:

  • 我的交互式bash shell进程( $
  • 一个子shell进程( bash -c ...
  • 睡眠儿童过程

但是,如果我的bash -c命令部分是单个命令,例如:

$ bash -c 'sleep 10'

然后吞下中间的子shell,并且我的交互式终端会话在孩子处理时“直接”执行睡眠。 进程树看起来像这样:

\\_ -bash \\_ sleep 10

所以从流程树的角度来看,这两个产生了相同的结果:

  • $ bash -c 'sleep 10'
  • $ sleep 10

这里发生了什么?

现在我的问题是:有没有办法强制中间shell,不管传递给bash -c ...的表达式的复杂性bash -c ...

(我可以追加类似的东西; echo;对我的实际命令和“工作”,但我宁愿没有。是否有更合适的方法来强制中间过程存在?)

(编辑: ps输出中的拼写错误;如评论中建议的那样删除了sh标记;还有一个拼写错误)

实际上,bash源中有一条评论描述了此功能的大部分原理:

/* If this is a simple command, tell execute_disk_command that it
   might be able to get away without forking and simply exec.
   This means things like ( sleep 10 ) will only cause one fork.
   If we're timing the command or inverting its return value, however,
   we cannot do this optimization. */
if ((user_subshell || user_coproc) && (tcom->type == cm_simple || tcom->type == cm_subshell) &&
    ((tcom->flags & CMD_TIME_PIPELINE) == 0) &&
    ((tcom->flags & CMD_INVERT_RETURN) == 0))
  {
    tcom->flags |= CMD_NO_FORK;
    if (tcom->type == cm_simple)
      tcom->value.Simple->flags |= CMD_NO_FORK;
  }

bash -c '...'情况下,当由should_suppress_fork builtins/evalstring.cshould_suppress_fork函数确定时, CMD_NO_FORK标志被设置。

让shell执行此操作总是对您有利。 它只发生在:

  • 输入来自硬编码字符串,shell位于该字符串中的最后一个命令。
  • 命令完成后,不再运行命令,陷阱,挂钩等。
  • 退出状态不需要反转或以其他方式修改。
  • 不需要撤消重定向。

这样可以节省内存,使进程的启动时间稍微快一些(因为它不需要fork ),并确保传递给PID的信号直接进入您正在运行的进程,从而使sh -c 'sleep 10'的父母确切地确定哪个信号杀死了sleep ,如果它实际上被信号杀死了。

但是,如果由于某种原因你想要禁止它,你需要设置陷阱 - 任何陷阱都会:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM