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

luv*_*eet 44 command-line

当我们打开它时终端正在运行。

luvpreet@DHARI-Inspiron-3542:/$
Run Code Online (Sandbox Code Playgroud)

我刚刚打开它。所以,当我按下Ctrl+ 时C,为什么它不自我杀死并关闭终端?

Zan*_*nna 50

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

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

另请参阅:有关信号的 Bash 初学者指南以及更深入的信号处理如何工作
注意:自从发表评论以来,此答案已被编辑

  • @chrylis 终端程序只是发送 ctrl-c 字符,实际上是内核 tty 层将其转换为信号。 (9认同)
  • 正确的术语是 shell 将“捕获”信号。不同的故事是当您从另一个窗口中启动终端窗口时。将 ctrl+c 发送到父窗口将杀死子进程。 (5认同)
  • @chrylis:终端或在其中运行的程序(例如文本编辑器)很可能将 Ctl-C 转换为其他一些操作。 (3认同)
  • 我认为按下 ctrl-c 时`bash` 不会终止任何程序。它只会告诉内核哪个进程组处于活动状态,当内核从终端程序接收到 ctrl-c 时,它会向该进程组生成一个信号。 (3认同)

chr*_*ic- 33

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

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

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

  • SysRq 真的很神奇。

  • Bash 不使用原始模式 - 它使用一次字符模式,即 `cbreak`/`-icanon`,但它确实保留了 `isig` 模式设置,并且在您按下映射的键时确实接收到真实信号给他们。它按照您描述的行为处理“SIGINT”(它不仅取消行编辑,还取消可能在循环中运行的任何内部命令),并完全忽略“SIGTSTP”和“SIGQUIT”。其他程序,例如 vi,可能不会。 (7认同)
  • “_cooked mode_(因为它不是生的)”:我……无语。这么多年过去了,我一直没有联系。 (2认同)

wal*_*tor 9

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

未捕获会SIGINT中断正在运行的进程,但是...

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

你所谓的“终端”会捕获SIGINT,然后继续工作。


use*_*833 7

当我还是初学者时,我错过了使用命令行时实际上使用两个独立程序,一个终端和一个 shell(例如 bash)的部分

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

另一边的终端就像是一个介于用户和程序(程序通常是 bash 或 fish 之类的 shell)之间的人。终端的作用是例如从键盘读取输入,可能以某种方式处理该输入,并将其重定向到另一个程序(bash)。

这也以另一种方式起作用,当另一个程序输出某些内容时,该某些内容被重定向到终端,然后终端的工作就是将该内容输出到屏幕上。在获取输入和将其打印到屏幕之间,终端可以以各种方式解释它获得的输入。

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

\e[0;31m some extra foobar text
Run Code Online (Sandbox Code Playgroud)

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

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


d a*_*s y 5

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

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

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

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

手册

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


trap理解:

trap是 shell 中内置的一个函数,用于响应硬件信号和其他事件。它定义并激活要在 shell 接收到信号或其他特殊条件时运行的处理程序。

trap [-lp] [arg] [sigspec …]
Run Code Online (Sandbox Code Playgroud)

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

当 shell 接收到信号 sigspec 时,arg 将被读取和执行。每个 sigspec 要么是信号名称,要么是信号编号。信号名称不区分大小写,SIG 前缀是可选的。

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

trap 'notify-send "Ctrl D pressed"' 0
Run Code Online (Sandbox Code Playgroud)

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

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

trap 'exit' INT
Run Code Online (Sandbox Code Playgroud)

或者

trap 'exit' 2
Run Code Online (Sandbox Code Playgroud)