Tôi muốn giết cả một cây quá trình. Cách tốt nhất để làm điều này bằng cách sử dụng bất kỳ ngôn ngữ kịch bản thông thường là gì? Tôi đang tìm kiếm một giải pháp đơn giản.
chronos
hoặc herodes
.
Tôi muốn giết cả một cây quá trình. Cách tốt nhất để làm điều này bằng cách sử dụng bất kỳ ngôn ngữ kịch bản thông thường là gì? Tôi đang tìm kiếm một giải pháp đơn giản.
chronos
hoặc herodes
.
Câu trả lời:
Bạn không nói nếu cây bạn muốn giết là một nhóm quy trình duy nhất. (Đây thường là trường hợp nếu cây là kết quả của việc bắt đầu từ máy chủ bắt đầu hoặc dòng lệnh shell.) Bạn có thể khám phá các nhóm quy trình bằng GNU ps như sau:
ps x -o "%p %r %y %x %c "
Nếu đó là một nhóm quy trình bạn muốn giết, chỉ cần sử dụng kill(1)
lệnh nhưng thay vì cho nó một số quy trình, hãy cho nó phủ định số nhóm. Ví dụ để tiêu diệt mọi quy trình trong nhóm 5112, hãy sử dụng kill -TERM -- -5112
.
pgrep
có thể cung cấp một cách dễ dàng hơn để tìm ID nhóm quy trình. Ví dụ: để giết nhóm quy trình của my-script.sh, hãy chạy kill -TERM -$(pgrep -o my-script.sh)
.
ps -o pid --no-headers --ppid $PARENT_PID
ps x -o "%r %p %y %x %c" | sort -nk1,2
Giết tất cả các quy trình thuộc cùng một cây quy trình bằng cách sử dụng ID nhóm quy trình ( PGID
)
kill -- -$PGID
Sử dụng tín hiệu mặc định ( TERM
= 15)kill -9 -$PGID
Sử dụng tín hiệu KILL
(9)Bạn có thể truy xuất PGID
từ bất kỳ ID quy trình ( PID
) nào của cùng một cây quy trình
kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*')
(tín hiệu TERM
)kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*')
(tín hiệu KILL
)Đặc biệt cảm ơn tanager và speakus vì những đóng góp trên $PID
các không gian còn lại và khả năng tương thích OSX.
kill -9 -"$PGID"
=> Gửi tín hiệu 9 ( KILL
) cho tất cả con và cháu ...PGID=$(ps opgid= "$PID")
=> Truy xuất ID nhóm quy trình từ bất kỳ ID quy trình nào của cây, không chỉ ID quy trình-cha mẹ . Một biến thể của ps opgid= $PID
là ps -o pgid --no-headers $PID
nơi pgid
có thể được thay thế bởi pgrp
. grep -o [0-9]*
chỉ in các chữ số liên tiếp (không in dấu cách hoặc tiêu đề bảng chữ cái).PGID=$(ps -o pgid= $PID | grep -o [0-9]*)
kill -TERM -"$PGID" # kill -15
kill -INT -"$PGID" # correspond to [CRTL+C] from keyboard
kill -QUIT -"$PGID" # correspond to [CRTL+\] from keyboard
kill -CONT -"$PGID" # restart a stopped process (above signals do not kill it)
sleep 2 # wait terminate process (more time if required)
kill -KILL -"$PGID" # kill -9 if it does not intercept signals (or buggy)
kill
được gọi bởi một quá trình thuộc cùng một cây, có kill
nguy cơ tự sát trước khi chấm dứt toàn bộ việc giết cây.> cat run-many-processes.sh
#!/bin/sh
echo "ProcessID=$$ begins ($0)"
./child.sh background &
./child.sh foreground
echo "ProcessID=$$ ends ($0)"
> cat child.sh
#!/bin/sh
echo "ProcessID=$$ begins ($0)"
./grandchild.sh background &
./grandchild.sh foreground
echo "ProcessID=$$ ends ($0)"
> cat grandchild.sh
#!/bin/sh
echo "ProcessID=$$ begins ($0)"
sleep 9999
echo "ProcessID=$$ ends ($0)"
Chạy cây quy trình trong nền bằng cách sử dụng '&'
> ./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
Lệnh pkill -P $PID
không giết cháu:
> 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
Lệnh kill -- -$PGID
giết tất cả các quá trình bao gồm cả cháu.
> 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
Tôi nhận thấy trong ví dụ này PID
và PGID
bằng ( 28957
).
Đây là lý do tại sao tôi nghĩ ban đầu kill -- -$PID
là đủ. Nhưng trong trường hợp quá trình này được sinh ra trong một Makefile
sự Process ID khác với Group ID .
Tôi nghĩ kill -- -$(ps -o pgid= $PID | grep -o [0-9]*)
là thủ thuật đơn giản tốt nhất để tiêu diệt toàn bộ cây quy trình khi được gọi từ ID nhóm khác (cây quy trình khác).
kill
nên luôn gửi tín hiệu đến toàn bộ cây trước khi nhận tín hiệu riêng. Nhưng trong một số trường hợp / việc triển khai cụ thể, kill
có thể gửi cho chính nó tín hiệu, bị gián đoạn và sau đó nhận tín hiệu của chính nó. Tuy nhiên, rủi ro phải đủ tối thiểu và có thể bị bỏ qua trong hầu hết các trường hợp vì các lỗi khác sẽ xảy ra trước lỗi này. Nguy cơ này có thể được bỏ qua trong trường hợp của bạn? Hơn nữa, các câu trả lời khác có lỗi phổ biến này ( kill
một phần của cây quá trình bị giết). Hy vọng sự giúp đỡ này .. Chúc mừng;)
man
cũng làm được điều đó. Mặt khác, nếu bạn muốn giết quá trình gandchild từ quá trình con, kill -- -$pid
sẽ không hoạt động. Vì vậy, nó không phải là giải pháp chung chung.
child.sh
.
pkill -TERM -P 27888
Điều này sẽ giết tất cả các quy trình có ID process 27888.
Hoặc mạnh mẽ hơn:
CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS
mà lịch trình giết chết 33 giây sau đó và lịch sự yêu cầu các quá trình chấm dứt.
Xem câu trả lời này để chấm dứt tất cả con cháu.
pkill -P
gửi tín hiệu cho trẻ => cháu không nhận được tín hiệu => Vì vậy, tôi đã viết một câu trả lời khác để giải thích điều đó. Chúc mừng ;-)
pkill -TERM -P ${$}
.
$ time for i in {1..32768}; do ( echo $BASHPID >> pids ); done real 0m18.860s
Để giết cây quy trình một cách đệ quy, hãy sử dụng killtree ():
#!/bin/bash
killtree() {
local _pid=$1
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 $0) <pid> [signal]"
exit 1
fi
killtree $@
--
đối số ps
không hoạt động trên OS X. Để làm cho nó hoạt động, hãy thay thế ps
lệnh bằng cách: ps ax -o "pid= ppid=" | grep -E "${_regex}" | sed -E "s/${_regex}/\1/g
where _regex
được xác định trước for
vòng lặp:local _regex="[ ]*([0-9]+)[ ]+${_pid}"
killtree()
hoạt động đáng tin cậy không?
ps
không hỗ trợ --ppid
, người ta có thể sử dụng pgrep -P ${_pid}
thay thế
Câu trả lời của brad là những gì tôi cũng khuyên bạn, ngoại trừ việc bạn có thể loại bỏ awk
hoàn toàn nếu bạn sử dụng --ppid
tùy chọn này ps
.
for child in $(ps -o pid -ax --ppid $PPID) do ....... done
nếu bạn biết vượt qua được quy trình chính, đây là tập lệnh shell sẽ hoạt động:
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
Tôi sử dụng một phiên bản sửa đổi một chút của một phương pháp được mô tả ở đây: https://stackoverflow.com/a/5311362/563175
Vì vậy, nó trông như thế:
kill `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`
Trong đó, 24901 là PID của cha mẹ.
Nó trông khá xấu xí nhưng nó hoạt động hoàn hảo.
pstree -p 24901 | grep -oP '(?<=\()[0-9]+(?=\))'
-l
vào pstree
, để các dòng dài không bị cắt ngắn; Nó cũng có thể được làm đơn giản hơn để đọc với kill `pstree -l -p 24901 |grep "([[:digit:]]*)" -o |tr -d '()'`
(không cần chuyển đổi \n
sang không gian vì nó sẽ hoạt động tốt), thx!
Phiên bản sửa đổi của câu trả lời của zhigang:
#!/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=$1 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
wait $pid
chỉ có thể trên các quy trình bạn đã bắt đầu, không phải tất cả các điều kiện tiên quyết, vì vậy đây không phải là một giải pháp chung
wait
sẽ ngăn chặn Terminated
tin nhắn nếu đó là một đứa trẻ.
Tôi không thể nhận xét (không đủ danh tiếng), vì vậy tôi buộc phải thêm một câu trả lời mới , mặc dù đây không thực sự là một câu trả lời.
Có một vấn đề nhỏ với câu trả lời rất hay và kỹ lưỡng khác được đưa ra bởi @olibre vào ngày 28 tháng 2. Đầu ra của ps opgid= $PID
sẽ chứa các khoảng trắng hàng đầu cho một PID ngắn hơn năm chữ số vì ps
điều chỉnh cột (sắp xếp các số). Trong toàn bộ dòng lệnh, điều này dẫn đến một dấu âm, theo sau là khoảng trắng, theo sau là nhóm PID. Giải pháp đơn giản là ống ps
để tr
đến chỗ loại bỏ:
kill -- -$( ps opgid= $PID | tr -d ' ' )
Để thêm vào câu trả lời của Norman Ramsey, có thể đáng để xem tại setsid nếu bạn muốn tạo một nhóm quy trình.
http://pub.opengroup.org/onlinepub/009695399/fifts/setsid.html
Hàm setsid () sẽ tạo một phiên mới, nếu quy trình gọi không phải là người lãnh đạo nhóm quy trình. Khi trả về, quy trình gọi sẽ là người lãnh đạo phiên của phiên mới này, sẽ là người lãnh đạo nhóm quy trình của nhóm quy trình mới và sẽ không có thiết bị đầu cuối kiểm soát. ID nhóm quy trình của quy trình gọi sẽ được đặt bằng ID quy trình của quy trình gọi. Quá trình gọi sẽ là quy trình duy nhất trong nhóm quy trình mới và là quy trình duy nhất trong phiên mới.
Điều tôi muốn nói là bạn có thể tạo một nhóm từ quá trình bắt đầu. Tôi đã sử dụng điều này trong php để có thể giết toàn bộ cây quy trình sau khi khởi động nó.
Đây có thể là một ý tưởng tồi. Tôi sẽ quan tâm đến ý kiến.
Lấy cảm hứng từ bình luận của ysth
kill -- -PGID
thay vì cho nó một số tiến trình, hãy cho nó phủ định số nhóm. Như thường lệ với hầu hết mọi lệnh, nếu bạn muốn một đối số bình thường bắt đầu bằng một
-
không được hiểu là một chuyển đổi, hãy đặt trước nó bằng--
PGID
từ PID
. Bạn nghĩ sao? Chúc mừng
Hàm shell sau đây tương tự như nhiều câu trả lời khác, nhưng nó hoạt động cả trên Linux và BSD (OS X, v.v.) mà không phụ thuộc bên ngoài như pgrep
:
killtree() {
local parent=$1 child
for child in $(ps -o ppid= -o pid= | awk "\$1==$parent {print \$2}"); do
killtree $child
done
kill $parent
}
$child
hàm đó để không làm phiền các biến khác (không cục bộ) có cùng tên và để đảm bảo giá trị của biến cục bộ được dọn sạch sau khi hàm kết thúc.
Thật dễ dàng để làm điều này với python bằng psutil . Chỉ cần cài đặt psutil với pip và sau đó bạn có một bộ công cụ thao tác quy trình đầy đủ:
def killChildren(pid):
parent = psutil.Process(pid)
for child in parent.get_children(True):
if child.is_running():
child.terminate()
Nếu bạn muốn giết một quá trình theo tên:
killall -9 -g someprocessname
hoặc là
pgrep someprocessname | xargs pkill -9 -g
Đây là phiên bản của tôi để giết tất cả các tiến trình con bằng cách sử dụng tập lệnh bash. Nó không sử dụng đệ quy và phụ thuộc vào lệnh pgrep.
Sử dụng
killtree.sh PID SIGNAL
Nội dung của killtrees.sh
#!/bin/bash
PID=$1
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=$2
if [ -z $SIGNAL ]
then
SIGNAL="TERM"
fi
#do substring from comma to space
kill -$SIGNAL ${PPLIST//,/ }
Đây là một biến thể của câu trả lời của @ zhigang mà không có AWK, chỉ dựa vào khả năng phân tích cú pháp riêng của Bash:
function killtree {
kill -STOP "$1"
ps -e -o pid= -o ppid= | while read -r pid ppid
do
[[ $ppid = $1 ]] || continue
killtree "$pid" || true # Skip over failures
done
kill -CONT "$1"
kill -TERM "$1"
}
Nó dường như hoạt động tốt trên cả máy Mac và Linux. Trong các tình huống mà bạn không thể dựa vào việc có thể quản lý các nhóm quy trình - như khi viết tập lệnh để kiểm tra một phần mềm phải được xây dựng trong nhiều môi trường - kỹ thuật đi trên cây này chắc chắn rất hữu ích.
Cảm ơn sự thông thái của bạn, folks. Kịch bản của tôi đã để lại một số tiến trình con khi thoát và mẹo phủ định giúp mọi việc dễ dàng hơn. Tôi đã viết hàm này để được sử dụng trong các tập lệnh khác nếu cần:
# 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 $1 in
-x) [ -n "$2" ] && kill -9 -$2 || kill -9 -$$ ;;
"") mainpid=$$ ;;
*) mainpid=$1 ;;
esac
prid=$(ps ax -o pid,pgid | grep $mainpid)
prid=${prid//$mainpid/}
kill -9 $prid 2>/dev/null
return
}
Chúc mừng.
Có lẽ tốt hơn là giết cha mẹ trước khi con cái; nếu không, cha mẹ có thể sinh ra những đứa trẻ mới một lần nữa trước khi anh ta tự sát. Những thứ này sẽ sống sót sau khi giết chóc.
Phiên bản ps của tôi khác với phiên bản trên; có lẽ đã quá cũ, do đó, sự kỳ lạ ...
Để sử dụng tập lệnh shell thay vì hàm shell có nhiều lợi thế ...
Tuy nhiên, về cơ bản, đó là ý tưởng của zhigang
#!/bin/bash
if test $# -lt 1 ; then
echo >&2 "usage: kiltree pid (sig)"
fi ;
_pid=$1
_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
Những điều sau đây đã được thử nghiệm trên FreeBSD, Linux và MacOS X và chỉ phụ thuộc vào pgrep và kill (các phiên bản ps -o không hoạt động theo BSD). Đối số đầu tiên là pid cha mẹ mà con cái phải được chấm dứt. đối số thứ hai là một boolean để xác định xem pid cha cũng phải được kết thúc hay không.
KillChilds() {
local pid="${1}"
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
Điều này sẽ gửi SIGTERM cho bất kỳ quá trình con / cháu nào trong tập lệnh shell và nếu SIGTERM không thành công, nó sẽ đợi 10 giây và sau đó gửi kill.
Câu trả lời trước đó:
Cách sau cũng hoạt động nhưng sẽ tự hủy shell trên BSD.
KillSubTree() {
local parent="${1}"
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
Tôi phát triển giải pháp của zhigang, xyuri và solidsneck hơn nữa:
#!/bin/bash
if test $# -lt 1 ; then
echo >&2 "usage: kiltree pid (sig)"
exit 1 ;
fi ;
_pid=$1
_sig=${2:-TERM}
# echo >&2 "killtree($_pid) mypid = $$"
# ps axwwf | grep -6 "^[ ]*$_pid " >&2 ;
function _killtree () {
local _children
local _child
local _success
if test $1 -eq $2 ; 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 $2 ;
_children=$(ps -o pid --no-headers --ppid $2) ;
_success=0
for _child in ${_children}; do
_killtree $1 ${_child} $3 ;
_success=$(($_success+$?)) ;
done ;
if test $_success -eq 0 ; then
kill -$3 $2
fi ;
# when a stopped process is killed, it will linger in the system until it is continued
kill -SIGCONT $2
test $_success -eq 0 ;
return $?
}
_killtree $$ $_pid $_sig
Phiên bản này sẽ tránh việc giết chết tổ tiên của nó - điều gây ra một loạt các quá trình con trong các giải pháp trước đó.
Các quy trình được dừng đúng cách trước khi danh sách con được xác định, do đó không có con mới nào được tạo hoặc biến mất.
Sau khi bị giết, các công việc bị dừng phải tiếp tục biến mất khỏi hệ thống.
Câu hỏi cũ, tôi biết, nhưng tất cả các câu trả lời dường như tiếp tục gọi ps, điều mà tôi không thích.
Giải pháp dựa trên awk này không yêu cầu đệ quy và chỉ gọi ps một lần.
awk 'BEGIN {
p=1390
while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2
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)
}'
Hoặc trên một dòng đơn:
awk 'BEGIN {p=1390;while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2;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)}'
Về cơ bản, ý tưởng là chúng ta xây dựng một mảng (a) cha mẹ: các mục con, sau đó lặp xung quanh mảng tìm con cho cha mẹ phù hợp của chúng ta, thêm chúng vào danh sách cha mẹ (p) khi chúng ta đi.
Nếu bạn không muốn giết quá trình cấp cao nhất, thì hãy làm
sub(/[0-9]*/, "", p)
ngay trước dòng system () sẽ xóa nó khỏi tập kill.
Hãy nhớ rằng có một điều kiện chủng tộc ở đây, nhưng đó là sự thật (theo như tôi có thể thấy) của tất cả các giải pháp. Nó làm những gì tôi cần bởi vì kịch bản tôi cần nó không tạo ra nhiều trẻ em sống ngắn.
Một bài tập cho người đọc sẽ là biến nó thành một vòng lặp 2 lượt: sau lần đầu tiên, gửi SIGSTOP đến tất cả các quy trình trong danh sách p, sau đó lặp lại để chạy lại ps và sau lần chuyển thứ hai gửi SIGTERM, sau đó là SIGCONT. Nếu bạn không quan tâm đến những kết thúc tốt đẹp thì thứ hai có thể chỉ là SIGKILL, tôi cho rằng.
Nếu bạn biết mấu chốt của thứ bạn muốn giết, bạn thường có thể đi từ id phiên và mọi thứ trong cùng một phiên. Tôi sẽ kiểm tra lại, nhưng tôi đã sử dụng điều này cho các tập lệnh bắt đầu rsyncs trong các vòng lặp mà tôi muốn chết, và không bắt đầu một đoạn khác (vì vòng lặp) như thể tôi sẽ giết rsync.
kill $(ps -o pid= -s $(ps -o sess --no-heading --pid 21709))
Nếu bạn không biết pid bạn vẫn có thể làm tổ
kill $(ps -o pid= -s $(ps -o sess --no-heading --pid $(pgrep rsync )))
ps -o pid= --ppid $PPID | xargs kill -9
kill -9
, thật đấy.
kill -15
sẽ không giúp đỡ.
Trong sh lệnh jobs sẽ liệt kê các tiến trình nền. Trong một số trường hợp, tốt hơn hết là giết quy trình mới nhất trước tiên, ví dụ như quy trình cũ hơn đã tạo ra một ổ cắm chung. Trong những trường hợp đó, sắp xếp các PID theo thứ tự ngược lại. Đôi khi bạn muốn chờ giây lát để các công việc viết một cái gì đó lên đĩa hoặc những thứ tương tự trước khi chúng dừng lại.
Và đừng giết nếu bạn không phải làm thế!
for SIGNAL in TERM KILL; do
for CHILD in $(jobs -s|sort -r); do
kill -s $SIGNAL $CHILD
sleep $MOMENT
done
done
Giết chết tiến trình con trong shell script:
Nhiều lúc chúng ta cần phải giết quá trình con bị treo hoặc chặn vì một số lý do. ví dụ. Sự cố kết nối FTP.
Có hai cách tiếp cận,
1) Để tạo cha mẹ mới riêng biệt cho mỗi đứa trẻ sẽ theo dõi và tiêu diệt quá trình con khi hết thời gian chờ.
Tạo test.sh như sau,
#!/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;
và xem các quá trình có tên là 'thử nghiệm' trong thiết bị đầu cuối khác bằng cách sử dụng lệnh sau.
watch -n1 'ps x -o "%p %r %c" | grep "test" '
Kịch bản trên sẽ tạo ra 4 tiến trình con mới và cha mẹ của chúng. Mỗi tiến trình con sẽ chạy trong 10 giây. Nhưng một khi hết thời gian tiếp cận 5sec, các quy trình cha mẹ tương ứng sẽ giết chết những đứa trẻ đó. Vì vậy, trẻ sẽ không thể hoàn thành việc thực hiện (10 giây). Chơi xung quanh các thời gian đó (chuyển 10 và 5) để xem hành vi khác. Trong trường hợp đó, đứa trẻ sẽ hoàn thành việc thực hiện trong 5 giây trước khi nó hết thời gian 10 giây.
2) Hãy để phụ huynh hiện tại giám sát và tiêu diệt tiến trình con khi hết thời gian chờ. Điều này sẽ không tạo ra cha mẹ riêng để theo dõi từng đứa trẻ. Ngoài ra, bạn có thể quản lý tất cả các quy trình con đúng trong cùng một cha mẹ.
Tạo test.sh như sau,
#!/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;
và xem các quá trình có tên là 'thử nghiệm' trong thiết bị đầu cuối khác bằng cách sử dụng lệnh sau.
watch -n1 'ps x -o "%p %r %c" | grep "test" '
Kịch bản trên sẽ tạo ra 4 tiến trình con mới. Chúng tôi đang lưu trữ các pids của tất cả các tiến trình con và lặp qua chúng để kiểm tra xem chúng đã hoàn thành việc thực thi hay vẫn đang chạy. Quá trình con sẽ thực thi cho đến thời gian CMD_TIME. Nhưng nếu đạt đến thời gian chờ của CNT_TIME_OUT, tất cả trẻ em sẽ bị giết bởi quy trình của cha mẹ. Bạn có thể chuyển thời gian và chơi xung quanh với tập lệnh để xem hành vi. Một nhược điểm của phương pháp này là, nó đang sử dụng id nhóm để giết tất cả cây con. Nhưng quá trình cha mẹ tự nó thuộc về cùng một nhóm nên nó cũng sẽ bị giết.
Bạn có thể cần gán id nhóm khác cho quy trình cha nếu bạn không muốn cha mẹ bị giết.
Nhiều thông tin thêm có thế được tìm thấy ở đây,
Tôi biết đó là cũ, nhưng đó là giải pháp tốt hơn mà tôi tìm thấy:
killtree() {
for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
echo Terminating: $p
kill $p
done
}