我有一个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
) &
我希望在运行的一些测试期间在后台运行以捕获进程信息。它运行&#34; ps&#34;有一些选项,然后睡了10分钟,我希望它无限期地运行(因为我的测试长度不同)。
我的问题是我无法阻止这种情况 - 做一个&#34; ps -ef&#34;只告诉我&#34;睡觉600&#34;命令,我无法打破循环。有没有办法杀死这个脚本或者更好地编写它以便不包括永无止境的循环?我唯一的想法是在一定的时间限制(即几组10分钟)之后编写脚本来结束执行,但我不希望在每次测试之前编辑脚本。
答案 0 :(得分:4)
( ... ) &
构造及其所有子构件调用的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 -NAME
和trap "..." NAME
不便携式外壳;但是,1到15 的信号数字的含义是全部的回到V7。如果完全可移植性不是最重要的问题,那么不要写一个shell脚本;当你想要获得一个不可移植的功能的那一刻,而是停止并重写整个东西在Perl中,它不仅是一种优秀的编程语言,而且在随机选择的Unix机器上可能比Bash更强更多。你未来的自我会感谢你。)
(对于学生们的说明:遗憾的是,没有现成的POSIX.1版本可以作为什么是便携式外壳的参考,因为几个主要的专有Unix供应商在1995年加上或减去他们的shell环境对于完整的可移植性,例如autoconf
脚本所需的,我不知道除了&#34之外的可靠测试;这是否适用于Solaris {{1}很高兴你不再需要挖掘对HP-UX,IRIX和AIX的访问权限。但是,我认为你可以代码到POSIX.1-2001,虽然不是 -2008,如果您只对开源BSD,全尺寸桌面或服务器Linux和OSX的可移植性感兴趣。我也在Android,busybox和其他各种嵌入式环境不的印象都提供了所有-2001。)
答案 1 :(得分:1)
有很多方法可以做到这一点。一个相对简单的就是这样:
FILENAME=/tmp/some_unusual_name_that_would_normally_never_exist
touch ${FILENAME}
while [[ -r ${FILENAME} ]]
do
ps ....
sleep ....
done
然后当你想杀死你的循环时,只需删除该文件即可。它会在下次检查时中止循环...
答案 2 :(得分:1)
我们在这里打高尔夫球,但如果不想等待600秒让它退出,你可以让它听一个命名管道(又名&#34; fifo&#34 ;)并在与管道对话后退出:
# 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