如何在Bash脚本被杀死时杀死当前命令

时间:2012-11-04 18:05:08

标签: linux bash shell sh kill

我目前有一个看起来像这样的脚本。

# code

mplayer "$vid"

# more code

问题是如果这个脚本被杀死,mplayer进程就会存在。我想知道我怎么能这样做,以便杀死脚本也会杀死mplayer。

我无法使用exec,因为我需要在mplayer之后运行命令。

exec mplayer "$vid"

我能想到的唯一可行解决方案是在后台生成它并等到手动完成。这样我可以得到它的PID并在脚本被杀死时杀死它,而不是完全优雅。我想知道这样做的“正确”或最佳方式是什么。

5 个答案:

答案 0 :(得分:4)

我能够在评论中测试我发布的prctl想法,它似乎有效。你需要编译这个:


#include "sys/prctl.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"

int main(int argc, char ** argv){

  prctl(PR_SET_PDEATHSIG, atoi(argv[1]),0,0,0);

  char * argv0 = strdup(argv[2]);

  char * slashptr = strrchr(argv0, '/');
  if(slashptr){
    argv0 = slashptr + 1;
  }

   return execvp(argv0, &(argv[2]));



}

假设您已将上述内容编译为名为“prun”的可执行文件,并且它位于您的路径中。假设您的脚本名为“foo.sh”,它也在您的路径中。制作一个调用

的包装脚本 prun 15 foo.sh

当包装器脚本因任何原因终止时,

foo.sh应该得到SIGTERM,甚至是SIGKILL。

注意:这是一个仅限Linux的解决方案,所提供的c源代码没有详细检查参数

答案 1 :(得分:3)

感谢Mux领先。除了手动捕获信号外,似乎没有办法在bash中执行此操作。这是最终的工作(过度评论)版本。

trap : SIGTERM SIGINT # Trap these two (killing) signals.  These will cause wait
                      # to return a value greater than 128 immediately after received.

mplayer "$vid" & # Start in background (PID gets put in `$!`)
pid=$!

wait $pid # Wait for mplayer to finish.
[ $? -gt 128 ] && { kill $pid ; exit 128; } ; # If a signal was recieved
                                              # kill mplayer and exit.

Refrences:   - 陷阱:http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html

答案 2 :(得分:2)

已更新)我想我理解您现在正在寻找的内容:

您可以通过生成一个新终端来运行您的脚本来完成此任务:

gnome-terminal -x /path_to_dir_of_your_script/your_script_name

(或使用xterm -ekonsole -e代替gnome-terminal -x,具体取决于您所使用的系统)

所以现在每当你的脚本结束/退出时(我假设你在脚本的某些部分有exit 0exit 1),新生成的终端也将退出,因为脚本已经完成 - 这将是反过来也会杀死在这个新终端下产生的任何应用程序。

例如,我刚用这个脚本测试了上面的命令:

#!/bin/bash

gedit &
pid=$!
echo "$pid"

sleep 5
exit 0

正如您所看到的,没有显式调用来终止新的gedit进程,但是一旦脚本退出,应用程序(gedit)就会关闭。

(以前的回答:或者,如果您只是询问如何杀死一个过程)以下是一个简短的示例,说明如何使用kill完成此任务。

#!/bin/bash

gedit &
pid=$!
echo "$pid"

sleep 5
kill -s SIGKILL $pid

除非我误解了您的问题,否则您可以立即获得生成过程的PID,而不是等到它完成。

答案 3 :(得分:2)

好吧,你可以简单地杀掉进程组,这样整个进程树就会被杀掉,先找出组ID

ps x -o  "%p %r  %c" | grep <name>

然后像这样使用kill:

kill -TERM -<gid>

请注意进程组ID之前的短划线。或者单行:

kill -TERM -$(pgrep <name>)

答案 4 :(得分:0)

也许使用command substitution在子shell中运行mplayer "$vid"

$(mplayer "$vid")

我用这种方式测试了它:

tesh.sh:

#!/bin/sh
$vid = "..."
$(mplayer "$vid")

% test.sh

在另一个终端:

% pkill test.sh

在原始终端中,mplayer停止,打印到stderr

Terminated
MPlayer interrupted by signal 13 in module: av_sync