为什么Ctrl-C不会杀死终端本身?


Answers:


48

Ctrl+ C是中断信号。在终端中键入此命令时,bash将SIGINT发送到前台的作业。如果没有工作(刚打开终端时就是这种情况),则什么也不会发生。终端仿真器程序不是在shell中运行的作业,因此,它不会收到信号且不会关闭。

如果要使用控制键关闭终端,请使用Ctrl+ D(EOF),这将导致bash退出(并也关闭终端)。

另请参阅:关于信号更深入的Bash初学者指南信号处理的工作原理
注意:自发布评论以来,此答案已被编辑。


4
正确的说法是外壳将“捕获”信号。当您从另一个窗口启动终端窗口时,情况就不同了。将ctrl + c发送到父窗口将杀死子进程。
Sergiy Kolodyazhnyy

1
此外,还可以指示GUI窗口捕获来自X11服务器的特定信号。这样便可以使弹出窗口通知您未保存的工作,或像在浏览器中一样打开选项卡
Sergiy Kolodyazhnyy

8
@chrylis终端程序只是发送ctrl-c字符,实际上是内核tty层将其转换为信号。
Random832

3
@chrylis:终端或终端中运行的程序(例如文本编辑器)可能会将Ctl-C转换为其他动作。
jamesqf

3
我认为bash按ctrl-c不会终止任何程序。它只会告诉内核哪个进程组处于活动状态,并且当内核从终端程序接收到ctrl-c时,内核将向该进程组生成信号。
卡巴斯德(Kasperd),

32

^C按键,像其他按键*,是不是魔术-它发送一个键码的那个程序具有焦点。(在X中,的键代码为54,对于的C修饰符为0x4 Ctrl。)接收键流的程序负责对它们进行适当的操作-请记住,在许多GUI应用程序中,键击均会复制到剪贴板。

当GUI终端仿真器(例如Konsole)或虚拟终端收到其解释为的按键时^C,它可以执行以下三种操作之一。如果终端处于原始模式,则正在运行的程序已要求终端不要对特殊键本身进行任何处理,并将其直接传递给程序。一些支持高级功能(例如行编辑)的程序会以某种配置在完整的原始击键和已处理的文本行之间接收键盘输入。bash例如,一次只接收一次击键。^C由终端解释,但退格键原样发送到外壳。

但是,大多数程序都使用熟模式(因为它不是原始模式),在这种模式下,终端会在实际将键击发送给程序之前先解释一些基本的键击(这就是为什么可以在中使用Backspace的原因cat)。在此模式下,终端本身会将^C按键转换为SIGINT信号,并将其发送给子进程。由于终端产生了信号,因此不会混淆和终止。

  • SysRq 真的是魔术。

显然这里不是超级相关,但是对于通用计算,那里有更多的魔术按键。最著名的是Windows世界中的Ctrl+ Alt+ Delete,其组合键非常接近魔术(可用于使Windows正常工作,这本身就是非常魔术!),因为它被硬编码到系统中以中断并覆盖几乎所有内容,与SysRq该意义上的内容非常相似。
KRyan

7
Bash不使用原始模式-它使用一次字符模式,即cbreak/ -icanon,但是它会保留该isig模式设置,并且在您按映射到键的键时会接收到真实信号。它SIGINT按照您所描述的方式进行处理(它不仅取消行编辑,还取消可能正在循环中运行的任何内部命令),并且完全忽略SIGTSTPSIGQUIT。其他程序,例如vi,可能没有。
Random832 '17

1
@KRyan Ctrl+ Alt+ Delete使用更加神奇的比今天- blogs.msdn.microsoft.com/oldnewthing/20140912-00/?p=44083。尽管我是一个Linux的人,但我常常对Windows在早期以有限的资源使用户友好和逻辑化的程度感到敬畏。
Muzer's

在某些OS上,即使另一个程序集中了系统(我猜是窗口管理器),也实际上在终端模拟器之前就获得了按键。如果您能够配置键盘快捷方式来捕捉窗口,打开应用程序,触发脚本,然后在将按下的键发送到终端仿真器之前,将检查它们是否已配置了任何快捷方式。还有一个示例,如果您没有打开任何应用程序,^c则不会终止窗口管理器:)。没能在上一次的东西生/熟人物评论,但得到的答复是现货关于怎么说击键产生SIGINT
阿贾伊

2
熟模式(因为它不是原始的)”:我...无语。这些年来,我从未建立联系。
isanae

8

^C通常映射(请参阅stty -a)到SIGINT信号(请参阅man 7 signal)。

未被捕获会SIGINT中断运行过程,但是...

SIGINT 是进程可以指定其行为的信号之一(“捕获信号”)。

您所谓的“终端”抓住了SIGINT,然后重新开始工作。


7

当我是一个初学者时,我缺少的部分是当我使用命令行时,我实际上使用的是两个单独的程序,即终端程序和外壳程序(例如bash)

shell是您可能已经知道的,该程序将输入命令或脚本作为输入,执行它们并输出其输出。

另一端的终端就像是位于用户和程序之间的中间人(该程序通常是bash或fish之类的shell)。终端要做的是例如从键盘上读取输入,也许以某种方式处理该输入,然后将其重定向到另一个程序(bash)。

同样,这也以另一种方式起作用,当其他程序输出某些内容时,会将某些内容重定向到终端,那么将这些内容输出到屏幕是终端的工作。在获取输入并将其打印到屏幕之间,终端可以以各种方式解释其获取的输入。

例如,如果程序输出以下序列:

\e[0;31m some extra foobar text

终端将在屏幕上输出带有红色字母的“一些额外的foobar文本”。这是因为终端选择以一种特殊的方式来处理该奇怪的代码,该代码提示它以红色打印以下输出。

类似地,当用户按下时Ctrl - C,唯一的特殊之处在于终端选择以特殊方式对其进行处理,此按键序列没有其他特殊之处。具体来说,这暗示它已将中断信号(SIGINT)发送到终端(即外壳)内部运行的进程。如果此时存在任何已由外壳生成的程序,并且当前正在前台运行,则它也会接收该信号。现在,外壳程序为此信号提供了一个特殊的处理程序,并且什么也没有发生。但是大多数程序都有默认的处理程序,在SIGINT的情况下,它们只是退出。


5

每个信号都有与之关联的默认操作。信号的默认操作是脚本或程序收到信号时执行的操作。

Ctrl+ C发送“中断”信号(SIGINT),默认为终止在前台运行的作业的进程。

Ctrl+ D告诉终端它应该在标准输入上注册EOF,bash将此解释为希望退出

一个进程可以选择忽略INT信号,当Bash在交互模式下运行时,它会这样做。

手册

当bash是交互式的时,在没有任何陷阱的情况下,它将忽略SIGTERM(这样,kill 0不会杀死一个交互式shell),并且SIGINT被捕获和处理(这样,wait内置函数是可中断的)。在所有情况下,bash都会忽略SIGQUIT。如果作业控制有效,则bash会忽略SIGTTIN,SIGTTOU和SIGTSTP。


陷阱了解它:

陷阱是内置在外壳中的功能,可响应硬件信号和其他事件。它定义并激活在外壳程序接收到信号或其他特殊情况时运行的处理程序。

trap [-lp] [arg] [sigspec …]

-l 打印信号名称及其对应编号的列表。
-p显示与每个SIGNAL_SPEC相关的陷阱命令。

当外壳收到信号sigspec时,将读取并执行arg。每个sigspec都是信号名称或信号编号。信号名称不区分大小写,并且SIG前缀是可选的。

如果sigspec0EXIT,则在退出shell时执行arg。要了解它,请关闭终端并在.bashrc文件中编辑以下行后将其打开。

trap 'notify-send "Ctrl D pressed"' 0

Ctrl D类似于exit从终端退出的命令。

如果您希望Bash在接收到INT信号后退出,即使在交互模式下,也可以将以下内容添加到您的~/.bashrc

trap 'exit' INT

要么

trap 'exit' 2

1
看来合法!
luv.preet
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.