bash shell 脚本中的信号处理

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22855462/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 10:07:16  来源:igfitidea点击:

Signal handling in a shell script

linuxbashshellsignalssh

提问by ernesto

Following is a shell script (myscript.sh) I have:

以下是我有的 shell 脚本 (myscript.sh):

#!/bin/bash

sleep 500 &

Aprogram arg1 arg2  # Aprogram is a program which runs for an hour.

echo "done"

I launched this in one terminal, and from another terminal I issued 'kill -INT 12345'. 12345 is the pid of myscript.sh.

我在一个终端上启动了这个,从另一个终端我发出了'kill -INT 12345'。12345 是 myscript.sh 的 pid。

After a while I can see that both myscript.sh and Aprogram have been dead. However 'sleep 500 &'is still running.

过了一会儿,我可以看到 myscript.sh 和 Aprogram 都已经死了。然而,'sleep 500 &'仍在运行。

Can anyone explain why is this behavior?

谁能解释为什么会出现这种行为?

Also, when I issued SIGINT signal to the 'myscript.sh'what exactly is happening? Why is 'Aprogram'getting killed and why not 'sleep'? How is the signal INT getting transmitted to it's child processes?

另外,当我向“myscript.sh”发出 SIGINT 信号时,到底发生了什么?为什么“Aprogram”被杀死,为什么不“睡眠”?信号 INT 如何传输到它的子进程?

采纳答案by pawel7318

After a while I can see that both myscript.sh and Aprogram have been dead. However 'sleep 500 &' is still running.

过了一会儿,我可以看到 myscript.sh 和 Aprogram 都已经死了。然而,'sleep 500 &' 仍在运行。

As soon as Aprogramis finished myscript.shprints "Done" and is also finised. sleep 500gets process with PID 1 as a parent. That is it.

一旦Aprogram完成myscript.sh打印“完成”并且也完成了。sleep 500以 PID 1 作为父进程获取进程。这就对了。

Can anyone explain why is this behavior?

谁能解释为什么会出现这种行为?

SIGINT is not deliverd to Aprogramwhen myscript.shgets it. Use straceto make sure that Aprogramdoes not receive a signal.

SIGINT 不会Aprogrammyscript.sh收到时传递给它。用于strace确保Aprogram没有接收到信号。

Also, when I issued SIGINT signal to the 'myscript.sh' what exactly is happening?

另外,当我向“myscript.sh”发出 SIGINT 信号时,到底发生了什么?

I first thought that it is the situation like when a user presses Ctrl-C and read this http://www.cons.org/cracauer/sigint.html. But it is not exactly the same situation. In your case shell received SIGINT but the child process didn't. However, shell had at that moment a child process and it did not do anything and kept waiting for a child. This is strace output on my computer after sending SIGINT to a shell script waiting for a child process:

我首先想到的是当用户按下 Ctrl-C 并阅读http://www.cons.org/cracauer/sigint.html 时的情况。但情况并不完全相同。在你的情况下,shell 收到了 SIGINT 但子进程没有。但是,此时shell有一个子进程,它什么也没做,一直在等待子进程。这是将 SIGINT 发送到等待子进程的 shell 脚本后,我计算机上的 strace 输出:

>strace -p 30484
Process 30484 attached - interrupt to quit
wait4(-1, 0x7fffc0cd9abc, 0, NULL)      = ? ERESTARTSYS (To be restarted)
--- SIGINT (Interrupt) @ 0 (0) ---
rt_sigreturn(0x2)                       = -1 EINTR (Interrupted system call)
wait4(-1,

Why is 'Aprogram' getting killed and why not 'sleep' ? How is the signal INT getting transmitted to it's child processes?

为什么“Aprogram”被杀死,为什么不“睡眠”?信号 INT 如何传输到它的子进程?

As far as I can see with stracea child program like your Aprogramis not getting killed. It did not receive SIGINT and finished normally. As soon as it finished your shell script also finished.

据我所知,strace像您这样的儿童程序Aprogram并没有被杀死。它没有收到 SIGINT 并正常完成。一旦完成,您的 shell 脚本也完成了。

回答by devnull

You start sleepin the background. As such, it is not killed when you kill the script.

你从sleep后台开始。因此,当您杀死脚本时,它不会被杀死。

If you want to kill sleeptoo when the script is terminated, you'd need to trapit.

如果您想sleep在脚本终止时也杀死trap它,则需要这样做。

sleep 500 &
sid=($!)                   # Capture the PID of sleep
trap "kill ${sid[@]}" INT   # Define handler for SIGINT

Aprogram arg1 arg2 & # Aprogram is a program which runs for an hour.
sid+=($!)
echo "done"

Nowsending SIGINTto your script would cause sleepto terminate as well.

现在发送SIGINT到您的脚本也会导致sleep终止。

回答by pawel7318

You need to use trapto catch signals:

您需要使用trap来捕捉信号:

To just ignore SIGINT use:

忽略 SIGINT 使用:

trap '' 2

if you want to specify some special action for this you can make it that in line:

如果您想为此指定一些特殊操作,您可以将其设置为:

trap 'some commands here' 2

or better wrap it into a function

或者更好地将它包装成一个函数

function do_for_sigint() {
 ...
}

trap 'do_for_sigint' 2

and if you wish to allow your script to finish all it's tasks first:

如果你想让你的脚本先完成它的所有任务:

keep_running="yes"

trap 'keep_running="no"' 2

while [ $keep_running=="yes" ]; do
 # main body of your script here
done