Старый вопрос, я знаю, но все ответы, кажется, продолжают вызывать ps, что мне не понравилось.
Это решение на основе awk не требует рекурсии и вызывает ps только один раз.
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)
}'
или в одну строку:
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)}'
По сути, идея состоит в том, что мы создаем массив (a) записей parent: child, затем зацикливаемся вокруг массива, находя дочерних элементов для наших подходящих родителей, добавляя их в наш список родителей (p) по мере продвижения.
Если вы не хотите убивать процесс верхнего уровня, тогда выполните
sub(/[0-9]*/, "", p)
непосредственно перед тем, как строка system () удалит его из набора уничтожений.
Имейте в виду, что здесь есть условие гонки, но это верно (насколько я вижу) для всех решений. Он делает то, что мне нужно, потому что сценарий, для которого он мне нужен, не создает много недолговечных детей.
Упражнение для читателя состояло бы в том, чтобы сделать его двухпроходным циклом: после первого прохода отправьте SIGSTOP всем процессам в списке p, затем выполните цикл для повторного запуска ps, а после второго прохода отправьте SIGTERM, затем SIGCONT , Если вы не заботитесь о хороших концах, то второй проход может быть просто SIGKILL, я полагаю.