Ctrl-C如何终止子进程?

vit*_*aut 63 bash shell process sh

我试图了解CTRL+ 如何C终止子进程而不是父进程.我在一些脚本shell中看到了这种行为,比如bash你可以在哪里开始一个长时间运行的进程然后通过输入来终止它CTRL- C然后控制返回到shell.

你能解释它是如何工作的,特别是为什么父(shell)进程没有终止?

shell是否必须对CTRL+ C事件进行一些特殊处理,如果是,它究竟是做什么的?

jm6*_*666 62

默认情况下,信号由内核处理.旧Unix系统有15个信号; 现在他们有更多.你可以检查</usr/include/signal.h>(或杀死-l).CTRL+ C是带名字的信号SIGINT.

处理每个信号的默认操作也在内核中定义,通常它会终止接收信号的进程.

所有信号(但SIGKILL)都可以由程序处理.

这就是shell的作用:

  • 当shell以交互模式运行时,它对此模式有一个特殊的信号处理.
  • 例如find,运行程序时,shell:
    • fork本身
    • 并为子设置默认信号处理
    • 用给定的命令替换孩子(例如用find)
    • 当你按CTRL+时C,父shell处理这个信号,但是孩子会收到它 - 用默认动作 - 终止.(孩子也可以实施信号处理)

您也可以trap在shell脚本中发出信号......

您也可以为交互式shell设置信号处理,尝试在您的顶部输入~/.profile.(确保您已经登录并使用其他终端进行测试- 您可以自行锁定)

trap 'echo "Dont do this"' 2
Run Code Online (Sandbox Code Playgroud)

现在,每次在shell中按CTRL+ C,它都会打印一条消息.别忘了删除该行!

如果有兴趣,可以/bin/sh这里检查源代码中的普通旧信号处理.

在上面的评论中有一些错误信息(现已删除),所以如果有兴趣的人是一个非常好的链接 - 信号处理如何工作.

  • SIGSTOP也是无法捕获的. (7认同)
  • 感谢您的解释和链接。《TTY 揭秘》是我见过的最好的介绍之一。 (2认同)
  • @PiotrDobrogost见男人.在评论中争论是没有意义的.如果您知道进程组的工作原理,那么您也知道将进程组设置为shell的作业.JeBP的回答(大部分)是正确的.主要是说,因为它只适用于具有作业控制的POSIX shell.基本原则仍然存在:shell为信号处理"做某事".它可以通过将信号处理程序设置为忽略来管理,或者(如JdeBP所说)可以与进程组一起使用. (2认同)
  • @PiotrDobrogost请记住,这里有许多shell和许多系统 - 而不是所有关心并与进程组一起玩.这是一个相当复杂的主题,并且不可能(普遍地)说:"一切都基于进程组" - 因为事实并非如此.在现实中 - 两个答案都是正确的.大多数现代炮弹(如bash)他的答案都是正确的,因为其他炮弹(例如`ash`或普通系统V炮弹 - 没有作业控制)是我的答案 - 他们通过信号处理来管理它.并且,信号处理方法是通用的.检查自己一些shell来源.就这样. (2认同)
  • @PiotrDobrogost最后,问问自己如何处理SIGHUP.(例如,当您向后台发送内容并断开控制终端时.(例如,生成SIGHUP信号的线路规则).谁收到它?(您知道 - 不仅是前台进程组.):) :) (2认同)

Jde*_*eBP 21

首先,阅读POSIX终端界面上的维基百科文章.

SIGINT信号是由终端线纪律产生,并且广播到终端的中的所有进程前台进程组.您的shell已经为您运行的命令(或命令管道)创建了一个新的进程组,并告诉终端该进程组是其(终端的)前台进程组.每个并发命令管道都有自己的进程组,前台命令管道是具有shell已编程到终端中作为终端的前台进程组的进程组的管道.在前台和后台之间切换"作业"(除了一些细节)是shell告诉终端哪个进程组现在是前台进程的问题.

shell进程本身位于另一个进程组中,因此当其中一个进程组位于前台时,它不会收到信号.就这么简单.


seh*_*ehe 7

终端将INT(中断)信号发送到当前连接到终端的进程.然后程序接收它,并可以选择忽略它,或退出.

没有任何进程被强行关闭(虽然默认情况下,如果你不处理sigint,我相信行为是打电话abort(),但我需要查看它).

当然,正在运行的进程与启动它的shell隔离开来.

如果您想要父shell,请使用以下命令启动您的程序exec:

exec ./myprogram
Run Code Online (Sandbox Code Playgroud)

这样,父shell将被子进程替换

  • @kobame:所以你说信号首先被发送到shell然后将它传递给子进程?为什么然后手动将SIGINT发送到shell并不会杀死孩子,例如'kill -2 <shell-pid>'对子进程没有任何作用,而Ctrl-C会杀掉它? (2认同)