如何从bash脚本中终止脚本的Cygwin bash中的进程树
我有一个Cygwin bash脚本,我需要在特定条件下观察并终止 - 具体来说,在创建某个文件后。不过,我很难理解如何以与Ctrl + C完全相同的级别终止脚本。如何从bash脚本中终止脚本的Cygwin bash中的进程树
这是一个简单的脚本(称为test1
),只是等待被终止。
#!/bin/bash
test -f kill_me && rm kill_me
touch kill_me
tail -f kill_me
如果这个脚本在前台运行,按Ctrl + C将终止两个tail
和脚本本身。如果脚本在后台运行,kill %1
(假设它是作业1)也将终止tail
和脚本。
但是,当我尝试从脚本执行相同的操作时,我发现只有运行脚本的bash
进程终止,而tail
挂起时与其父级断开连接。这里有一种方法我试过(test2
):
#!/bin/bash
test -f kill_me && rm kill_me
(
touch kill_me
tail -f kill_me
) &
while true; do
sleep 1
test -f kill_me && {
kill %1
exit
}
done
如果这样运行,在bash在后台运行的子shell终止OK,但仍tail
周围挂起。
如果我使用一个显式单独的脚本,这样,它仍然不起作用(test3
):
#!/bin/bash
test -f kill_me && rm kill_me
# assuming test1 above is included in the same directory
./test1 &
while true; do
sleep 1
test -f kill_me && {
kill %1
exit
}
done
tail
运行此脚本后,仍挂在。
在我的实际案例中,创建文件的过程并不是特别可操作的,所以我无法自己终止它;通过查明它何时创建了一个特定的文件,我可以在那一刻知道终止它是可以的。不幸的是,我不能使用一个简单的killall
或等价物,因为可能有多个实例在运行,而我只想杀死特定的实例。
/bin/kill(程序,而不是bash内建函数)将作为负值 PID解释为“杀死进程组”,这也会让所有的孩子都得到。
更改
kill %1
到
/bin/kill -- -$$
为我工作。
This script看起来像它会做的工作:
#!/bin/bash
# Author: Sunil Alankar
##
# recursive kill. kills the process tree down from the specified pid
#
# foreach child of pid, recursive call dokill
dokill() {
local pid=$1
local itsparent=""
local aprocess=""
local x=""
# next line is a single line
for x in `/bin/ps -f | sed -e '/UID/d;s/[a-zA-Z0-9_-]\{1,\}
\{1,\}\([0-9]\{1,\}\) \{1,\}\([0-9]\{1,\}\) .*/\1 \2/g'`
do
if [ "$aprocess" = "" ]; then
aprocess=$x
itsparent=""
continue
else
itsparent=$x
if [ "$itsparent" = "$pid" ]; then
dokill $aprocess
fi
aprocess=""
fi
done
echo "killing $1"
kill -9 $1 > /dev/null 2>&1
}
case $# in
1) PID=$1
;;
*) echo "usage: rekill <top pid to kill>";
exit 1;
;;
esac
dokill $PID
该脚本在Cygwin中未修复,但它是一个起点。 Upvoted,但在我自己的答案中有一个工作脚本。 – 2009-02-07 19:05:28
亚当的链接把我会解决这个问题,虽然不无一些小的警告方向。
这个脚本在Cygwin下无法修改,所以我重写了它,并提供了更多的选项。这里是我的版本:
#!/bin/bash
function usage
{
echo "usage: $(basename $0) [-c] [-<sigspec>] <pid>..."
echo "Recursively kill the process tree(s) rooted by <pid>."
echo "Options:"
echo " -c Only kill children; don't kill root"
echo " <sigspec> Arbitrary argument to pass to kill, expected to be signal specification"
exit 1
}
kill_parent=1
sig_spec=-9
function do_kill # <pid>...
{
kill "$sig_spec" "[email protected]"
}
function kill_children # pid
{
local target=$1
local pid=
local ppid=
local i
# Returns alternating ids: first is pid, second is parent
for i in $(ps -f | tail +2 | cut -b 10-24); do
if [ ! -n "$pid" ]; then
# first in pair
pid=$i
else
# second in pair
ppid=$i
((ppid == target && pid != $$)) && {
kill_children $pid
do_kill $pid
}
# reset pid for next pair
pid=
fi
done
}
test -n "$1" || usage
while [ -n "$1" ]; do
case "$1" in
-c)
kill_parent=0
;;
-*)
sig_spec="$1"
;;
*)
kill_children $1
((kill_parent)) && do_kill $1
;;
esac
shift
done
唯一真正的缺点是有点丑陋消息Bash打印出来,当它接收到一个致命的信号,即“终止”,“封杀”或“追访”(这取决于你送什么) 。不过,我可以在批处理脚本中使用它。
谢谢!奇怪的是,这并没有在Cygwin kill man页面中记录。但是,它确实与Cygwin版本的kill相配合。 – 2009-02-09 10:15:06