如何杀死一个经常睡觉的Unix进程?

我有一个Unix shell脚本,如下所示:

( # Trap the HUP signal so it doesn't kill me trap "" HUP # Redirect stderr to /dev/null exec 2>/dev/null # Redirect stdin from /dev/null exec 0</dev/null # Redirect stdout to logfile exec 1>${LOG} while [ 1 ] do ps -ewwo pcpu,pid,ppid,comm,time,etime,thcount,scount,fuser,args | grep -v "migration" | grep -v "watchdog" | grep -v "ksoftirqd" sleep 600 done ) & 

我想在运行一些testing的时候在后台运行,以捕获进程信息。 它用一些选项运行“ps”,然后睡10分钟,我希望它无限期运行(因为我的testing长度不一)。

我的问题是,我没有办法阻止这个 – 做一个“ps -ef”只显示“睡眠600”命令,我没有办法打破循环。 有没有办法杀死这个脚本,还是最好写一下,以免包含一个永无止境的循环? 我唯一的想法是编写脚本在一定的时间限制(即多个10分钟)后结束执行,但我宁愿不必在每次testing之前编辑脚本。

( ... ) &构造函数调用的shell子进程及其所有子进程将处于其自己的进程组中

 $ ps -e -o pid,pgid,ppid,tty,comm PID PGID PPID TT COMMAND ... 2827 2827 2147 pts/1 bash 2832 2827 2827 pts/1 sleep ... 

通过指定一个负数作为要kill的进程ID,可以在一个操作中杀死整个进程组。 (为此,您还必须指定一个信号编号。)

 $ kill -15 -2827 [2]+ Terminated ( trap "" HUP; exec 2> /dev/null; ... 

要杀死的PGID保证等于其进程组首部的PID,在这种情况下,它是shell子进程 。 所以你可以修改你的代码

 ( # Trap the HUP signal so it doesn't kill me trap "" 1 # ... ) & # the special shell variable $! contains the PID of the most recently # started background process SUBPROCESS="$!" # and later when you want to shut it all down again kill -15 "-$SUBPROCESS" # ensuring the subprocess is killed with the script would also be a good idea trap "kill -15 '-$SUBPROCESS'" 0 1 2 3 15 

(注意: kill -NAMEtrap "..." NAME 不是可移植的shell;但是,信号编号​​1到15的含义可移植的,一直回到V7,如果可移植性不是最重要的问题, 编写一个shell脚本 ;当你想要达到一个不可移植的功能的时候,停下来用Perl重新编写整个东西,这不仅是一种优秀的编程语言,它可能在一个随机选择的Unix盒子上而不是Bash上是的,你未来的自我会感谢你。)

(请注意:不幸的是,没有现成的POSIX.1版本可以作为可移植shell的参考,因为几个主要的专有Unix厂商在1995年前后两年内冻结了他们的shell环境。 完整的可移植性,例如autoconf脚本所要求的,我不知道除了“这是否适用于Solaris /bin/sh ?”之外,还有一个可靠的测试吗?(非常高兴您不再需要挖掘对HP-UX的访问权限, IRIX和AIX)。然而,我的印象是,你可以编码到POSIX.1-2001,尽管不是 -2008,如果你只是对开源BSD的便携性感兴趣,那么全尺寸桌面或者服务器Linux和OSX,我也觉得Android,busybox和其他各种嵌入式环境提供-2001的全部功能)。

有很多方法可以做到这一点。 一个相对容易的会是这样的:

 FILENAME=/tmp/some_unusual_name_that_would_normally_never_exist touch ${FILENAME} while [[ -r ${FILENAME} ]] do ps .... sleep .... done 

然后当你想杀死你的循环,只要删除文件。 它会在下一次检查时中止循环。

我们正在这里打高尔夫球,但是如果不想等待600秒退出,你可以在有名管道(又名“fifo”)上听,然后一旦进入管道就退出:

 # this will be our fifo pipe=/tmp/testpipe # remove it when we exit trap "rm -f $pipe" EXIT # take care of our children if we're killed trap "kill -15 '-$$'" 0 1 2 3 15 # create the pipe if [[ ! -p $pipe ]]; then mkfifo $pipe fi # put it in a function so we can background it function ps_and_sleep() { while [ 1 ] do ps -ewwo pcpu,pid,ppid,comm,time,etime,thcount,scount,fuser,args | grep -v "migration" | grep -v "watchdog" | grep -v "ksoftirqd" sleep 600 done } #... and background it ps_and_sleep & # the moment somebody does this: # echo stopitnow > /tmp/testpipe # then we'll get the message, kill the child, and exit if read line <$pipe; then kill -15 -$$ exit fi 

道具http://www.linuxjournal.com/content/using-named-pipes-fifos-bash