Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 如何在终止Bash脚本时终止当前命令_Linux_Bash_Shell_Sh_Kill - Fatal编程技术网

Linux 如何在终止Bash脚本时终止当前命令

Linux 如何在终止Bash脚本时终止当前命令,linux,bash,shell,sh,kill,Linux,Bash,Shell,Sh,Kill,我有一个脚本,看起来像这样 # code mplayer "$vid" # more code 问题是,如果此脚本被终止,mplayer进程将继续运行。我想知道我如何才能做到这样,杀死脚本也会杀死mplayer 我不能使用exec,因为我需要在mplayer之后运行命令 exec mplayer "$vid" 我能想到的唯一可能的解决方案是在后台生成它,并等待它手动完成。这样我就可以得到它的PID,并在脚本被杀死时杀死它,这不是很优雅。我想知道做这件事的“正确”或最好的方法是什么。(更新

我有一个脚本,看起来像这样

# code

mplayer "$vid"

# more code
问题是,如果此脚本被终止,mplayer进程将继续运行。我想知道我如何才能做到这样,杀死脚本也会杀死mplayer

我不能使用
exec
,因为我需要在mplayer之后运行命令

exec mplayer "$vid"
我能想到的唯一可能的解决方案是在后台生成它,并等待它手动完成。这样我就可以得到它的PID,并在脚本被杀死时杀死它,这不是很优雅。我想知道做这件事的“正确”或最好的方法是什么。

更新了)我想我了解您现在在寻找什么:

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

gnome-terminal -x /path_to_dir_of_your_script/your_script_name
(或使用
xterm-e
konsole-e
而不是
gnome terminal-x
,具体取决于您所使用的系统)

因此,现在每当脚本结束/退出时(我假设脚本的某些部分中有
exit 0
exit 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,而不是等到它完成。

好吧,您可以简单地杀死进程组,这样整个进程树都会被杀死,首先找到组id

ps x -o  "%p %r  %c" | grep <name>
ps x-o“%p%r%c”| grep
然后像这样使用kill:

kill -TERM -<gid>
kill-TERM-
注意过程组id前的破折号。或一个衬里:

kill -TERM -$(pgrep <name>)
kill-TERM-$(pgrep)
可能用于在子shell中运行
mplayer“$vid”

$(mplayer "$vid")

我是这样测试的:

tesh.sh:

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

在单独的终端中:

% pkill test.sh
在原始终端中,mplayer停止,打印到stderr

Terminated
MPlayer interrupted by signal 13 in module: av_sync

感谢Mux的领导。在bash中,除了手动捕获信号外,似乎没有其他方法可以做到这一点。这里是一个最终的工作(过度评论)版本

参考资料:
-陷阱:

我能够测试我在评论中发布的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源代码没有详细检查参数

问题是我没有终止我的脚本。它正在被一个我(无论出于何种目的)无法控制的程序运行和终止。@KevinCox在这种情况下,除了捕获信号和终止子进程,或者类似的事情,我看不到其他方法。没那么糟糕。问题是我没有运行我的脚本,它正在运行我的另一个程序。@KevinCox哪个程序正在运行你的脚本?你能让程序执行
gnome terminal-x/path\u to\u dir\u of_your_script/u script\u name
而不仅仅是脚本的名称吗?XScreensaver。我想我可以,但它肯定不会那么优雅。如果找不到更好的,我会这么做。我认为这是最好的答案。终端正在为您发送信号,因此您不必捕获并发送自己的信号。我认为,您所做的任何事情本质上都是重新实现术语imal所做的事情。如果您在linux上,您可以尝试将当前脚本包装到另一个脚本中,然后在包装器被终止(甚至被SIGKILL终止)时将您选择的一个信号发送到当前脚本,然后您可以使用它终止进程树。请看:虽然我不知道如何从shell脚本调用prctl…但您无法捕获信号9。它会立即终止进程。如果能抓住它,那就没用了。不幸的是,这种情况无法处理。事实上,我做了一些研究,(xfce-)终端有办法做到这一点。我将进一步研究它(将SIGKILL添加到陷阱中不起作用)。我似乎与会话有关。我有一个狙击手,当放置在脚本顶部时,会导致mplayer在被杀死时死亡。不幸的是,由于某些原因,这在xscreensaver中不起作用,xscreensaver实际上将脚本设置为会话控制器。这可能是xscreensaver中的一个bug,或者mplayer可能正在做一些有趣的事情。这真的很棒(还没有测试过,但我假设它可以工作)。不过,如果有一个bash解决方案,那就太棒了。我想我会接受这个答案,即使我的答案是我计划使用的答案(我不太担心SIGKILL),因为这个答案完全解决了这个问题。另外,你想在这个相关问题()上重新发布或添加这个答案的链接吗,因为这是一个比其他给出的答案更好的答案。好的,我试了一下,发现里面有一些虫子。我修复了它,提交并编辑了它。旧剧本是在听父母的死亡,但它是父母。新脚本
fork
s,孩子要求在
exec
ing之前接收父母的死亡。我还删除了名称mangling,因为它对于不在路径上或当前目录中的文件无效。我使用exec it设置它的方式是,它被设计为由shell脚本包装。当shell脚本死亡时,无论
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.

#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]));



}