bash Ctrl-C 如何终止子进程?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6108953/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does Ctrl-C terminate a child process?
提问by vitaut
I am trying to understand how CTRL+Cterminates a child but not a parent process. I see this behavior in some script shells like bash
where you can start some long-running process and then terminate it by entering CTRL-Cand the control returns to the shell.
我试图了解CTRL+如何C终止子进程而不是父进程。我在一些脚本 shell 中看到了这种行为,比如bash
你可以开始一些长时间运行的进程,然后通过输入终止它CTRL-C并且控制返回到 shell。
Could you explain how does it work and in particular why isn't the parent (shell) process terminated?
你能解释一下它是如何工作的,特别是为什么父(shell)进程没有终止?
Does the shell have to do some special handling of CTRL+Cevent and if yes what exactly does it do?
shell 是否必须对CTRL+C事件进行一些特殊处理,如果是,它究竟是做什么的?
采纳答案by jm666
Signals by default are handled by the kernel. Old Unix systems had 15 signals; now they have more. You can check </usr/include/signal.h>
(or kill -l). CTRL+Cis the signal with name SIGINT
.
默认情况下,信号由内核处理。旧的 Unix 系统有 15 个信号;现在他们有更多。您可以检查</usr/include/signal.h>
(或kill -l)。CTRL+C是名称为 的信号SIGINT
。
The default action for handling each signal is defined in the kernel too, and usually it terminates the process that received the signal.
处理每个信号的默认动作也在内核中定义,通常它会终止接收信号的进程。
All signals (but SIGKILL
) can be handled by program.
所有信号(但SIGKILL
)都可以由程序处理。
And this is what the shell does:
这就是 shell 的作用:
- When the shell running in interactive mode, it has a special signal handling for this mode.
- When you run a program, for example
find
, the shell:fork
s itself- and for the child set the default signal handling
- replace the child with the given command (e.g. with find)
- when you press CTRL+C, parent shell handle this signal but the child will receive it - with the default action - terminate. (the child can implement signal handling too)
- 当 shell 在交互模式下运行时,它对这种模式有一个特殊的信号处理。
- 例如
find
,当您运行一个程序时,shell:fork
本身- 并为孩子设置默认信号处理
- 用给定的命令替换子元素(例如用 find)
- 当您按下CTRL+ 时C,父 shell 会处理此信号,但子 shell 将接收它 - 使用默认操作 - 终止。(孩子也可以实现信号处理)
You can trap
signals in your shell script too...
你也可以trap
在你的 shell 脚本中发出信号......
And you can set signal handling for your interactive shell too, try enter this at the top of you ~/.profile
. (Ensure than you're a already logged in and test it with anotherterminal - you can lock out yourself)
你也可以为你的交互式 shell 设置信号处理,尝试在你的顶部输入它~/.profile
。(确保您已经登录并使用另一个终端进行测试- 您可以锁定自己)
trap 'echo "Dont do this"' 2
Now, every time you press CTRL+Cin your shell, it will print a message. Don't forget to remove the line!
现在,每次在 shell 中按CTRL+C时,它都会打印一条消息。不要忘记删除该行!
If interested, you can check the plain old /bin/sh
signal handling in the source code here.
如果有兴趣,您可以/bin/sh
在此处查看源代码中的普通旧信号处理。
At the above there were some misinformations in the comments (now deleted), so if someone interested here is a very nice link - how the signal handling works.
在上面的评论中有一些错误信息(现已删除),所以如果有人对此感兴趣,这是一个非常好的链接 -信号处理如何工作。
回答by JdeBP
First, read the Wikipedia article on the POSIX terminal interfaceall of the way through.
首先,完整阅读维基百科上关于 POSIX 终端界面的文章。
The SIGINT
signal is generated by the terminal line discipline, and broadcast to all processes in the terminal's foreground process group. Your shell has already created a new process group for the command (or command pipeline) that you ran, and told the terminal that that process group is its (the terminal's) foreground process group. Every concurrent command pipeline has its own process group, and the foregroundcommand pipeline is the one with the process group that the shell has programmed into the terminal as the terminal's foreground process group. Switching "jobs" between foreground and background is (some details aside) a matter of the shell telling the terminal which process group is now the foreground one.
该SIGINT
信号由终端线路规程生成,并广播给终端前台进程组中的所有进程。您的 shell 已经为您运行的命令(或命令管道)创建了一个新进程组,并告诉终端该进程组是其(终端的)前台进程组。每个并发命令管道都有自己的进程组,前台命令管道是将 shell 编程到终端中的进程组作为终端的前台进程组。在前台和后台之间切换“作业”是(撇开一些细节)外壳告诉终端哪个进程组现在是前台进程组的问题。
The shell process itself is in yet another process group all of its own and so doesn't receive the signal when one of those process groups is in the foreground. It's that simple.
shell 进程本身位于另一个进程组中,因此当其中一个进程组在前台时不会收到信号。就这么简单。
回答by sehe
The terminal sends the INT (interrupt) signal to the process that is currently attached to the terminal. The program then receives it, and could choose to ignore it, or quit.
终端向当前连接到终端的进程发送 INT(中断)信号。然后程序接收它,并且可以选择忽略它或退出。
No process is necessarily being forcibly closed (although by default, if you don't handle sigint, I believe the behaviour is to call abort()
, but I'd need to look that up).
没有必要强制关闭进程(尽管默认情况下,如果您不处理 sigint,我相信行为是调用abort()
,但我需要查找)。
Of course, the running process is isolated from the shell that launched it.
当然,正在运行的进程与启动它的 shell 是隔离的。
If you wantedthe parent shell to go, launch your program with exec
:
如果您希望父 shell 运行,请使用以下命令启动您的程序exec
:
exec ./myprogram
That way, the parent shell is replaced by the child process
这样,父shell就被子进程替换了