2009-02-07 135 views
3

我有一個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或等價物,因爲可能有多個實例在運行,而我只想殺死特定的實例。

回答

6

/bin/kill(程序,而不是bash內建函數)將作爲負值 PID解釋爲「殺死進程組」,這也會讓所有的孩子都得到。

更改

kill %1 

/bin/kill -- -$$ 

爲我工作。

+0

謝謝!奇怪的是,這並沒有在Cygwin kill man頁面中記錄。但是,它確實與Cygwin版本的kill相配合。 – 2009-02-09 10:15:06

1

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 
+0

該腳本在Cygwin中未修復,但它是一個起點。 Upvoted,但在我自己的答案中有一個工作腳本。 – 2009-02-07 19:05:28

2

亞當的鏈接把我會解決這個問題,雖然不無一些小的警告方向。

這個腳本在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打印出來,當它接收到一個致命的信號,即「終止」,「封殺」或「追訪」(這取決於你送什麼) 。不過,我可以在批處理腳本中使用它。