bash 运行程序后会在后台做什么?

bash 运行程序后会在后台做什么?

终端的输入是否通过 bash 进程路由到当前正在运行的程序,或者终端是否与 bash 进程“断开”并连接到新程序,以防止 bash 拦截或干扰?

bash 是否只是在后台冻结,等待您开始关闭的程序,还是正在做一些事情?

当我关闭终端窗口时,我是否向 bash 发送信号,而 bash 又向前台进程发送信号以关闭它们?或者我是否向前台进程发送信号,该信号向上传播到 bash?

答案1

终端的输入是否通过 bash 进程路由到当前正在运行的程序,或者终端是否与 bash 进程“断开”并连接到新程序,以防止 bash 拦截或干扰?

两者都不。假设一个没有管道或重定向的简单前台命令...来自用户的输入和返回给用户的输出不会通过 bash 路由。但是 bash 并没有被阻止干扰,bash 根本就没有尝试干扰。

当程序打开任何文件或终端时,它会收到一个用于读取和写入的文件描述符。 子进程继承父进程的打开文件描述符集的副本。

当您在终端输入内容时,它会通过标准输入传递给进程。当它向用户写入内容时,它会写入 stdout 或 stderr。 Stdin、stdout 和 stderr 都是具有可预测 ID 的文件描述符:根据 POSIX 标准,它们分别编号为 0 1 2。因此,当 bash 运行程序时,它首先创建子进程并且子进程自动继承相同的 stdin、stdout 和 stderr FD。因此,孩子将自动读取和写入完全相同的终端。

注意“运行程序”是通过调用完成的然后执行。管道和重定向是通过调用替换 stdin、stdout 和 stderr 来实现的杜普2fork 和 execve 之间。

所以“程序”可以直接从与 bash 相同的终端读取。这不会阻止 bash 或其他任何东西读取和写入同一终端。如果 bash 真的尝试这样做,可能会造成混乱。多个进程写入会导致所有内容都以不可预测的顺序写入。多个进程读取会导致一些字节(击键)进入一个进程,而另一些则进入另一个进程。

bash 是否只是在后台冻结,等待您开始关闭的程序,还是正在做一些事情?

它有效地冻结。更准确地说,它在等待。据我所知它明确调用waitpid()或者wait3()(取决于您运行 shell 的 Unix),等待子进程终止。

当我关闭终端窗口时,我是否向 bash 发送信号,而 bash 又向前台进程发送信号以关闭它们?或者我是否向前台进程发送信号,该信号向上传播到 bash?

抱歉,我无法立即记住这种行为。我相信关闭终端[窗口]通常会杀死正在运行的进程,即使它不读取或写入任何内容,因此我不相信它是基于导致 EOF 的终端读取。我相信关闭终端会导致信号。如果找到正确的答案,我会编辑答案。

我确实知道有些孩子可以有效地拦截键盘中断键序列,防止 bash 接收它们。我不确定这是否意味着他们正在拦截信号或只是禁止终端一起生成信号。

答案2

尚未提出的问题是:当您异步启动进程(使用 & )时会发生什么以及为什么这与键入不带 & 的命令不同?

这里重要的东西叫做“继承”。当您的交互式 shell 无事可做时,它会显示您的提示符(PS1 变量)并在其标准输入上进行读取。它之所以挂起,是因为窗口管理器在启动时没有击键可写入它创建的与 shell 对话的流。

如果您键入命令名称,shell 将“分叉”(复制)自身,并且子进程从 shell 继承 stdin、stdout、stderr。然后,子 shell 告诉内核将命令加载到自身上(“execve”)。

问题是,窗口管理器现在有两个进程读取同一流——原始 shell 和子命令。该怎么办?谁会阅读您输入的下一个内容?

对于同步“前台”子级,子级命令应该获取数据。因此 shell 不会在 stdin 上进行读取。相反,它会进入睡眠状态,当子进程退出并且其退出状态可用时,它预计会被 SIGCHLD 唤醒。所以没有办法告诉它启动第二个前台子进程,

对于异步“后台”子进程,该子进程将在标准输入断开的情况下分叉(连接到 /dev/null)。 Stdout 和 stderr 仍然连接(除非它们被重定向),因此异步进程仍然可以发送到终端(尽管行同步可能是随机的)。然后 shell 发出提示符并等待下一个命令(例如,可能是“jobs”)。它可以启动其他异步进程,或者一次运行一个命令,或者处理内置的 shell 命令,因此您可以同时执行许多后台作业。当每个异步子进程退出时,它仍然会收到 SIGCHLD,并且它可以收集状态,将其从作业列表中删除,等等。

我怀疑,当您关闭终端时,外壳程序会在从中获取窗口输入的流上获取 EOF。它使用启动每个子项时设置的内部列表来终止其所有子项。

答案3

需要理解的一个重要区别是终端和 Shell 之间的区别。终端是您用来输入命令、读取文本和接收计算机屏幕上的程序输出的界面。另一方面,Shell 是负责通过与内核交互来执行程序的实体。

您的终端不会“挂起”。它在“等待”shell 完成该过程时不会显示新的提示。您可以在同一台机器上使用多个终端(这就是我们tmux的能力!)。

当您在终端上输入命令或运行程序时,终端会解析您的按键并将其传递给 shell,然后 shell 将通过解析您的输入来运行该过程。一旦输入被传递给 shell,终端就完成了它的工作。它现在所做的就是等待脚本结束。

这个解释也应该回答你的最后一个问题。当您关闭终端屏幕时,该信号将传播到当前正在运行的程序以终止它。

相关内容