Каков наилучший способ отправить сигнал всем членам группы процессов?


Я хочу убить целое дерево процессов. Каков наилучший способ сделать это с помощью любых распространенных языков сценариев? Я ищу простое решение.

30 395

30 ответов:

вы не говорите, что дерево, которое вы хотите убить, является одной группой процессов. (Это часто бывает, если дерево является результатом разветвления от запуска сервера или командной строки оболочки.) Вы можете обнаружить группы процессов с помощью GNU ps следующим образом:

 ps x -o  "%p %r %y %x %c "

Если это группа процессов, которую вы хотите убить, просто используйте kill(1) команда, но вместо того, чтобы дать ему номер процесса, дайте ему отрицание номер группы. Например, чтобы убить любой процесс в группе 5112, используйте kill -TERM -- -5112.

убить все процессы, принадлежащие к одному и тому же дерево процессов С помощью ID группы процессов (PGID)

  • kill -- -$PGID использовать сигнал по умолчанию (TERM = 15)
  • kill -9 -$PGID использовать сигнал KILL (9)

вы можете получить PGID любой Process-ID (PID) из той же )" ./child.sh background & ./child.sh foreground echo "ProcessID=$$ ends ()" > cat child.sh #!/bin/sh echo "ProcessID=$$ begins ()" ./grandchild.sh background & ./grandchild.sh foreground echo "ProcessID=$$ ends ()" > cat grandchild.sh #!/bin/sh echo "ProcessID=$$ begins ()" sleep 9999 echo "ProcessID=$$ ends ()"

запустите дерево процессов в фоновом режиме с помощью '&'

> ./run-many-processes.sh &    
ProcessID=28957 begins (./run-many-processes.sh)
ProcessID=28959 begins (./child.sh)
ProcessID=28958 begins (./child.sh)
ProcessID=28960 begins (./grandchild.sh)
ProcessID=28961 begins (./grandchild.sh)
ProcessID=28962 begins (./grandchild.sh)
ProcessID=28963 begins (./grandchild.sh)

> PID=$!                    # get the Parent Process ID
> PGID=$(ps opgid= "$PID")  # get the Process Group ID

> ps fj
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28348 28349 28349 28349 pts/3    28969 Ss   33021   0:00 -bash
28349 28957 28957 28349 pts/3    28969 S    33021   0:00  \_ /bin/sh ./run-many-processes.sh
28957 28958 28957 28349 pts/3    28969 S    33021   0:00  |   \_ /bin/sh ./child.sh background
28958 28961 28957 28349 pts/3    28969 S    33021   0:00  |   |   \_ /bin/sh ./grandchild.sh background
28961 28965 28957 28349 pts/3    28969 S    33021   0:00  |   |   |   \_ sleep 9999
28958 28963 28957 28349 pts/3    28969 S    33021   0:00  |   |   \_ /bin/sh ./grandchild.sh foreground
28963 28967 28957 28349 pts/3    28969 S    33021   0:00  |   |       \_ sleep 9999
28957 28959 28957 28349 pts/3    28969 S    33021   0:00  |   \_ /bin/sh ./child.sh foreground
28959 28960 28957 28349 pts/3    28969 S    33021   0:00  |       \_ /bin/sh ./grandchild.sh background
28960 28964 28957 28349 pts/3    28969 S    33021   0:00  |       |   \_ sleep 9999
28959 28962 28957 28349 pts/3    28969 S    33021   0:00  |       \_ /bin/sh ./grandchild.sh foreground
28962 28966 28957 28349 pts/3    28969 S    33021   0:00  |           \_ sleep 9999
28349 28969 28969 28349 pts/3    28969 R+   33021   0:00  \_ ps fj

команда pkill -P $PID не убивает внука:

> pkill -P "$PID"
./run-many-processes.sh: line 4: 28958 Terminated              ./child.sh background
./run-many-processes.sh: line 4: 28959 Terminated              ./child.sh foreground
ProcessID=28957 ends (./run-many-processes.sh)
[1]+  Done                    ./run-many-processes.sh

> ps fj
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28348 28349 28349 28349 pts/3    28987 Ss   33021   0:00 -bash
28349 28987 28987 28349 pts/3    28987 R+   33021   0:00  \_ ps fj
    1 28963 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh foreground
28963 28967 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999
    1 28962 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh foreground
28962 28966 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999
    1 28961 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh background
28961 28965 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999
    1 28960 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh background
28960 28964 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999

команда kill -- -$PGID убивает все процессы, включая внука.

> kill --    -"$PGID"  # default signal is TERM (kill -15)
> kill -CONT -"$PGID"  # awake stopped processes
> kill -KILL -"$PGID"  # kill -9 to be sure

> ps fj
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28348 28349 28349 28349 pts/3    29039 Ss   33021   0:00 -bash
28349 29039 29039 28349 pts/3    29039 R+   33021   0:00  \_ ps fj

вывод

я заметил в этом примере PID и PGID равны (28957).
Вот почему я первоначально думал kill -- -$PID было достаточно. Но в случае, если процесс нерестится в пределах Makefile the идентификатор процесса отличается от ID группы.

я думаю kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) лучший простой трюк, чтобы убить все дерево процесса при вызове из другой ID группы (другое дерево процессов).

pkill -TERM -P 27888

Это убьет все процессы, которые имеют идентификатор родительского процесса 27888.

или более надежные:

CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS

который график убийства 33 секунд спустя и вежливо попросить процессы прекратить.

посмотреть ответ для прекращения всех потомков.

чтобы рекурсивно убить дерево процессов, используйте killtree ():

#!/bin/bash

killtree() {
    local _pid=
    local _sig=${2:--TERM}
    kill -stop ${_pid} # needed to stop quickly forking parent from producing children between child killing and parent killing
    for _child in $(ps -o pid --no-headers --ppid ${_pid}); do
        killtree ${_child} ${_sig}
    done
    kill -${_sig} ${_pid}
}

if [ $# -eq 0 -o $# -gt 2 ]; then
    echo "Usage: $(basename ) <pid> [signal]"
    exit 1
fi

killtree $@

rkill С pslist пакет посылает данный сигнал (или SIGTERM по умолчанию) для указанного процесса и всех его потомков:

rkill [-SIG] pid/name...

бред-это то, что я бы тоже рекомендовал, за исключением того, что вы можете покончить с awk в целом, если вы используете до ps.

for child in $(ps -o pid -ax --ppid $PPID) do ....... done

Если вы знаете, передайте pid родительского процесса, вот сценарий оболочки, который должен работать:

for child in $(ps -o pid,ppid -ax | \
   awk "{ if ( $2 == $pid ) { print $1 }}")
do
  echo "Killing child process $child because ppid = $pid"
  kill $child
done

Я использую немного измененную версию метода, описанного здесь: https://stackoverflow.com/a/5311362/563175

Так выглядит так:

kill `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*//' | tr "\n" " "`

где 24901-ПИД родителя.

это выглядит довольно уродливо, но делает это работа отлично.

измененная версия ответа Жигана:

#!/usr/bin/env bash
set -eu

killtree() {
    local pid
    for pid; do
        kill -stop $pid
        local cpid
        for cpid in $(pgrep -P $pid); do
            killtree $cpid
        done
        kill $pid
        kill -cont $pid
        wait $pid 2>/dev/null || true
   done
}

cpids() {
    local pid= options=${2:-} space=${3:-}
    local cpid
    for cpid in $(pgrep -P $pid); do
        echo "$space$cpid"
        if [[ "${options/a/}" != "$options" ]]; then
            cpids $cpid "$options" "$space  "
        fi
    done
}

while true; do sleep 1; done &
cpid=$!
for i in $(seq 1 2); do
    cpids $$ a
    sleep 1
done
killtree $cpid
echo ---
cpids $$ a

чтобы добавить к ответу Нормана Рэмси, возможно, стоит посмотреть на setsid, если вы хотите создать процесс group.
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html

функция setsid() должна создать новый сеанс, если вызывающий процесс не лидер группы процессов. На возврат вызывающий процесс должен быть руководитель сессии этого нового сессия, будет группа процесса лидером новой группы процессов , и не имеет управляющего терминала. Идентификатор группы процессов вызова процесс должен быть установлен равным идентификатор вызывающего процесса. Этот вызывающий процесс должен быть единственным процесса в группе процессов и единственный процесс в новой сессии.

что я понимаю, что вы можете создать группу из начального процесса. Я использовал это в php, чтобы иметь возможность убить целое дерево процессов после его запуска.

Это может быть плохо идея. Я был бы заинтересован в комментариях.

Я не могу комментировать (не хватает репутации), поэтому я вынужден добавить новый ответ, хотя это не совсем ответ.

есть небольшая проблема с другим очень хорошим и тщательным ответом, данным @olibre 28 февраля. Выход ps opgid= $PID будет содержать ведущие пробелы для PID короче пяти цифр, потому что ps оправдывает столбец (rigth выравнивает числа). В пределах всей командной строки это приводит к отрицательному знаку, за которым следует пробел(ы), за которым следует группа PID. Простое решение-труба ps до tr для удаления пробелов:

kill -- -$( ps opgid= $PID | tr -d ' ' )

вдохновленный комментарий ysth

kill -- -PGID

вместо того, чтобы дать ему номер процесса, дайте ему отрицание группы число. Как обычно с почти любой командой, если вы хотите нормальный аргумент, который начинается с - чтобы не интерпретироваться как переключатель, предшествуйте ему с --

следующая функция оболочки похожа на многие другие ответы, но она работает как на Linux, так и на BSD (OS X и т. д.) без внешних зависимостей, таких как pgrep:

killtree() {
    local parent= child
    for child in $(ps -o ppid= -o pid= | awk "$1==$parent {print $2}"); do
        killtree $child
    done
    kill $parent
}

это очень легко сделать с помощью python с помощью psutil. Просто установите psutil с pip, а затем у вас есть полный набор инструментов управления процессом:

def killChildren(pid):
    parent = psutil.Process(pid)
    for child in parent.get_children(True):
        if child.is_running():
            child.terminate()

основываясь на ответе Жигана, это позволяет избежать самоуничтожения:

init_killtree() {
    local pid= child

    for child in $(pgrep -P $pid); do
        init_killtree $child
    done
    [ $pid -ne $$ ] && kill -kill $pid
}

Если вы хотите убить процесс по имени:

killall -9 -g someprocessname

или

pgrep someprocessname | xargs pkill -9 -g

Это моя версия убийства всех дочерних процессов с помощью сценария bash. Он не использует рекурсию и зависит от команды pgrep.

использовать

killtree.sh PID SIGNAL

содержание killtrees.sh

#!/bin/bash
PID=
if [ -z $PID ];
then
    echo "No pid specified"
fi

PPLIST=$PID
CHILD_LIST=`pgrep -P $PPLIST -d,`

while [ ! -z "$CHILD_LIST" ]
do
    PPLIST="$PPLIST,$CHILD_LIST"
    CHILD_LIST=`pgrep -P $CHILD_LIST -d,`
done

SIGNAL=

if [ -z $SIGNAL ]
then
    SIGNAL="TERM"
fi
#do substring from comma to space
kill -$SIGNAL ${PPLIST//,/ }

вот вариант ответа @zhigang, который делает без AWK, полагаясь только на собственные возможности синтаксического анализа Bash:

function killtree {
  kill -STOP ""
  ps -e -o pid= -o ppid= | while read -r pid ppid
                           do
                             [[ $ppid =  ]] || continue
                             killtree "$pid"  || true # Skip over failures
                           done
  kill -CONT ""          
  kill -TERM ""
}

похоже, он отлично работает как на Mac, так и на Linux. В ситуациях, когда вы не можете полагаться на возможность управлять группами процессов-например, при написании сценариев для тестирования программного обеспечения, которое должно быть построено в нескольких средах-этот метод ходьбы по дереву определенно полезен.

вероятно, лучше убить родителя до детей; в противном случае родитель может, вероятно, породить новых детей снова, прежде чем он убьет себя. Они переживут убийство.

моя версия ps отличается от приведенной выше; возможно, слишком стара, поэтому странная grepping...

использование сценария оболочки вместо функции оболочки имеет много преимуществ...

однако, это в основном идея Жиганов


#!/bin/bash
if test $# -lt 1 ; then
    echo >&2 "usage: kiltree pid (sig)"
fi ;

_pid=
_sig=${2:-TERM}
_children=$(ps j | grep "^[ ]*${_pid} " | cut -c 7-11) ;
echo >&2 kill -${_sig} ${_pid}
kill -${_sig} ${_pid}
for _child in ${_children}; do
    killtree ${_child} ${_sig}
done

следующее было протестировано на FreeBSD, Linux и MacOS X и зависит только от pgrep и kill (версии ps-o не работают под BSD). Первый аргумент-это родительский pid, дочерние элементы которого должны быть завершены. второй аргумент является логическим, чтобы определить, должен ли Родительский pid быть также завершен.

KillChilds() {
        local pid=""
        local self="${2:-false}"

        if children="$(pgrep -P "$pid")"; then
                for child in $children; do
                        KillChilds "$child" true
                done
        fi

        if [ "$self" == true ]; then
                kill -s SIGTERM "$pid" || (sleep 10 && kill -9 "$pid" &)
        fi
}

KillChilds $$ > /dev/null 2>&1

это отправит SIGTERM в любой дочерний / внучатый процесс в сценарии оболочки, и если SIGTERM не удастся, он будет ждать 10 секунд, а затем отправить убивать.


ранее в ответ:

следующее также работает, но убьет сам снаряд на BSD.

KillSubTree() {
    local parent=""
    for child in $(ps -o pid=$parent); do
            if [ $$ -ne $child ]; then (kill -s SIGTERM $child || (sleep 10 && kill -9 $child & )) > /dev/null 2>&1 ; fi
    done
}
# Example lanch from within script
KillSubTree $$ > /dev/null 2>&1

Я разрабатываю решение zhigang, xyuri и solidsneck дальше:

 #!/bin/bash

if test $# -lt 1 ; then
    echo >&2 "usage: kiltree pid (sig)"
    exit 1 ;
  fi ;

_pid=
_sig=${2:-TERM}

# echo >&2 "killtree($_pid) mypid = $$"
# ps axwwf | grep -6 "^[ ]*$_pid " >&2 ;

function _killtree () {
    local _children
    local _child
    local _success

    if test  -eq  ; then # this is killtree - don't commit suicide!
        echo >&2 "killtree can´t kill it´s own branch - some processes will survive." ; 
        return 1 ;
      fi ;
    # this avoids that children are spawned or disappear.
    kill -SIGSTOP  ;

    _children=$(ps -o pid --no-headers --ppid ) ;        
    _success=0 
    for _child in ${_children}; do
        _killtree  ${_child}  ;
        _success=$(($_success+$?)) ;
      done ;

    if test $_success -eq 0 ; then
        kill - 
      fi ;
    # when a stopped process is killed, it will linger in the system until it is continued
    kill -SIGCONT 
    test $_success -eq 0 ;
    return $?
    }

_killtree $$ $_pid $_sig

эта версия позволит избежать убийства своей родословной-что вызывает поток дочерних процессов в предыдущих решениях.

процессы должным образом останавливаются до определения дочернего списка, так что новые дочерние элементы не создаются и не исчезают.

после уничтожения остановленные задания должны продолжать исчезать из системы.

старый вопрос, я знаю, но все ответы, похоже, продолжают называть ps, что мне не понравилось.

Это решение на основе awk не требует рекурсии и вызывает ps только один раз.

awk 'BEGIN {
  p=1390
  while ("ps -o ppid,pid"|getline) a[]=a[]" "
  o=1
  while (o==1) {
    o=0
    split(p, q, " ")
    for (i in q) if (a[q[i]]!="") {
      p=p""a[q[i]]
      o=1
      a[q[i]]=""
    }
  }
  system("kill -TERM "p)
}'

или на одной строке:

awk 'BEGIN {p=1390;while ("ps -o ppid,pid"|getline) a[]=a[]" ";o=1;while (o==1) {o=0;split(p, q, " ");for (i in q) {if (a[q[i]]!="") {p=p""a[q[i]];o=1;a[q[i]]=""}}}system("kill -TERM "p)}'

В основном идея заключается в том, что мы создаем массив (a) родительских:дочерних записей, а затем петлю вокруг массива поиска детей для наших соответствующих родителей, добавляя их в список наших родителей (p), как мы идем.

Если вы не хотите убить процесс верхнего уровня, а затем делать

sub(/[0-9]*/, "", p)

как раз перед тем, как строка system() удалит ее из набора убийств.

имейте в виду, что здесь есть гонки, но это правда (насколько я вижу) из всех решений. Он делает то, что мне нужно, потому что сценарий, в котором я нуждался, не создает много недолговечных детей.

упражнение для читателя состояло бы в том, чтобы сделать его циклом 2 прохода: после первого прохода отправьте SIGSTOP всем процессам в список p, затем цикл для запуска ps снова и после второго прохода отправить SIGTERM, а затем SIGCONT. Если вы не заботитесь о хороших концовках, то второй проход может быть просто SIGKILL, я полагаю.

Я знаю, что это старый, но это лучшее решение, которое я нашел:

killtree() { 
    for p in $(pstree -p  | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
        echo Terminating: $p 
        kill $p
    done
}

Спасибо за вашу мудрость, люди. Мой скрипт оставлял некоторые дочерние процессы на выходе и отрицание совет сделал вещи легче. Я написал эту функцию для использования в других скриптах, если это необходимо:

# kill my group's subprocesses:          killGroup
# kill also myself:                      killGroup -x
# kill another group's subprocesses:     killGroup N  
# kill that group all:                   killGroup -x N
# N: PID of the main process (= process group ID).

function killGroup () {
    local prid mainpid
    case  in
        -x) [ -n "" ] && kill -9 - || kill -9 -$$ ;;
        "") mainpid=$$ ;;
         *) mainpid= ;;
    esac
    prid=$(ps ax -o pid,pgid | grep $mainpid)
    prid=${prid//$mainpid/}
    kill -9 $prid 2>/dev/null
    return
}

Ура.

если у вас есть pstree и perl в вашей системе, вы можете попробовать это:

perl -e 'kill 9, (`pstree -p PID` =~ m/\((\d+)\)/sg)'

Если вы знаете pid вещи, которую вы хотите убить, вы обычно можете перейти от идентификатора сеанса, и все в том же сеансе. Я бы дважды проверил, но я использовал это для сценариев запуска rsyncs в циклах, которые я хочу умереть, а не запускать другой (из-за цикла), как это было бы, если бы я просто убил rsync.

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid 21709))

Если вы не знаете пид вы все еще можете вложить больше

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid $(pgrep rsync )))
ps -o pid= --ppid $PPID | xargs kill -9 

в sh команда jobs выведет список фоновых процессов. В некоторых случаях может быть лучше сначала убить самый новый процесс, например, более старый создал общий сокет. В этих случаях сортируйте PIDs в обратном порядке. Иногда вы хотите дождаться момента, когда задания запишут что-то на диск или что-то подобное, прежде чем они остановятся.

и не убивайте, если вам это не нужно!

for SIGNAL in TERM KILL; do
  for CHILD in $(jobs -s|sort -r); do
    kill -s $SIGNAL $CHILD
    sleep $MOMENT
  done
done

убийство дочернего процесса в сценарии оболочки:

много раз нам нужно убить дочерний процесс, который повешен или блокируется по какой-то причине. например. Проблема с подключением FTP.

есть два подхода,

1) чтобы создать отдельный новый родитель для каждого ребенка, который будет контролировать и убивать дочерний процесс после достижения таймаута.

создать test.sh как следует,

#!/bin/bash

declare -a CMDs=("AAA" "BBB" "CCC" "DDD")
for CMD in ${CMDs[*]}; do
    (sleep 10 & PID=$!; echo "Started $CMD => $PID"; sleep 5; echo "Killing $CMD => $PID"; kill $PID; echo "$CMD Completed.") &
done
exit;

и смотреть процессы, которые имеют имя как "тест" в другом терминале с помощью выполнить следующую команду.

watch -n1 'ps x -o "%p %r %c" | grep "test" '

выше скрипт создаст 4 новых дочерних процессов и их родителей. Каждый дочерний процесс будет выполняться в течение 10 сек.но как только тайм-аут достигнет 5 сек, их соответствующие родительские процессы убьют этих детей. Таким образом, ребенок не сможет завершить выполнение(10sec). Играть вокруг этих таймингов(переключатель 10 и 5), чтобы увидеть другое поведение. В этом случае ребенок завершит выполнение в 5sec, прежде чем он достигнет таймаута 10sec.

2) Пусть текущий родитель монитор и убить дочерний процесс, как только тайм-аут достигнут. Это не создаст отдельного родителя для мониторинга каждого ребенка. Также вы можете правильно управлять всеми дочерними процессами в пределах одного родителя.

создать test.sh как следует,

#!/bin/bash

declare -A CPIDs;
declare -a CMDs=("AAA" "BBB" "CCC" "DDD")

CMD_TIME=15;
for CMD in ${CMDs[*]}; do
    (echo "Started..$CMD"; sleep $CMD_TIME; echo "$CMD Done";) &
    CPIDs[$!]="$RN";
    sleep 1;
done

GPID=$(ps -o pgid= $$);
CNT_TIME_OUT=10;
CNT=0;
while (true); do
    declare -A TMP_CPIDs;

    for PID in "${!CPIDs[@]}"; do
        echo "Checking "${CPIDs[$PID]}"=>"$PID;

        if ps -p $PID > /dev/null ; then
          echo "-->"${CPIDs[$PID]}"=>"$PID" is running..";
          TMP_CPIDs[$PID]=${CPIDs[$PID]};
        else
          echo "-->"${CPIDs[$PID]}"=>"$PID" is completed.";
        fi
    done

    if [ ${#TMP_CPIDs[@]} == 0 ]; then
        echo "All commands completed.";
        break;
    else
        unset CPIDs;
        declare -A CPIDs;
        for PID in "${!TMP_CPIDs[@]}"; do
            CPIDs[$PID]=${TMP_CPIDs[$PID]};
        done
        unset TMP_CPIDs;

        if [ $CNT -gt $CNT_TIME_OUT ]; then
            echo ${CPIDs[@]}"PIDs not reponding. Timeout reached $CNT sec. killing all childern with GPID $GPID..";
            kill -- -$GPID;
        fi
    fi

    CNT=$((CNT+1));
    echo "waiting since $b secs..";
    sleep 1;
done

exit;

и смотреть процессы, которые имеют имя как "тест" в другом терминале, используя следующую команду.

watch -n1 'ps x -o "%p %r %c" | grep "test" '

выше скрипт создаст 4 новых дочерних процессов. Мы храним pids всех дочерних процессов и перебираем их, чтобы проверить, если они закончили свое исполнение или все еще работают. Дочерний процесс будет выполняться до времени CMD_TIME. Но если время ожидания CNT_TIME_OUT достигнет, все дети будут убиты родительским процессом. Вы можете переключать время и играть со скриптом, чтобы увидеть поведение. Одним из недостатков этого подхода является использование идентификатора группы для уничтожения всего дочернего дерева. Но сам родительский процесс принадлежит к той же группе, поэтому он также будет убит.

необходимо назначить другой ID группы родителя, если не хочу, чтобы родителя убили.

более подробную информацию можно найти здесь

убийство дочернего процесса в сценарии оболочки

этот скрипт тоже работает:

#/bin/sh while true do echo "Enter parent process id [type quit for exit]" read ppid if [ $ppid -eq "quit" -o $ppid -eq "QUIT" ];then exit 0 fi for i in `ps -ef| awk ' == '$ppid' { print }'` do echo killing $i kill $i done done