Изменение Python по умолчанию (или Perl, и т.д.) на ОС является действительно плохой идеей. Этот интерпретатор является на самом деле частью ОС и могут быть другие компоненты ОС, которые записаны конкретно для работы с той версией интерпретатора.
Например, на Redhat вкусный инструмент, который выполняет обновления системного программного обеспечения, является приложением Python. Вы действительно не хотите повреждать это. Такие приложения могут зависеть от определенного, возможно, нестандартного, модули Python, устанавливаемые, который не может иметь версия, которую Вы установили. Например, на Ubuntu я полагаю, что некоторые встроенные инструменты OS, записанные в Python, используют ORM, названный Storm, который не является частью библиотеки стандарта Python. Ваша чистая установка Python 2.7 имеет определенную ожидаемую версию модуля Storm установленной? Это имеет какую-либо версию Storm? Нет? Затем Вы только что повредили блок своей ОС.
Правильный способ сделать это - установка Ваша предпочтительная версия Python и настроило Вашу учетную запись пользователя для использования его путем установки .bash_profile, пути и такого. Вы могли бы также хотеть изучить virtualenv модуль для Python.
Следующее несколько более просто, и имеет добавленное преимущество игнорирования чисел на названия команды:
pstree -p $pid | grep -o '([0-9]\+)' | grep -o '[0-9]\+'
Или с Perl:
pstree -p $pid | perl -ne 'print "$1\n" while /\((\d+)\)/g'
Мы ищем числа в круглых скобках так, чтобы мы, например, не давали 2 как дочерний процесс, когда мы натыкаемся gif2png(3012)
. Но если название команды содержит заключенное в скобки число, все ставки выключены. Существует только до сих пор обработка текста, может взять Вас.
Таким образом, я также думаю, что группы процесса являются способом пойти. Если требуется выполнить процесс в его собственной группе процесса, можно использовать 'pgrphack' инструмент от пакета Debian 'daemontools':
pgrphack my_command args
Или Вы могли снова обратиться к Perl:
perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args
Единственный протест здесь состоит в том, что группы процесса не вкладывают, поэтому если некоторый процесс создаст свои собственные группы процесса, то его подпроцессы больше не будут в группе, которую Вы создали.
Самая короткая версия я нашел, что также имеет дело правильно с командами как pop3d
:
pstree -p $pid | perl -ne 's/\((\d+)\)/print " $1"/ge'
Это имеет дело неправильно, если у Вас есть команды, которые имеют странные имена как: my(23)prog
.
В каждом из Ваших двух (по-видимому очень искусственных) вариантов использования, почему Вы хотите уничтожить подпроцессы некоторого неудачного процесса? Как Вы знаете лучше, чем процесс, когда его дети должны жить или умереть? Это походит на плохой дизайн мне; процесс должен вымыться после себя.
Если Вы действительно знаете лучше, то необходимо разветвлять эти подпроцессы, и 'daemonized процесс' является по-видимому слишком немым, чтобы доверяться к fork(2)
.
Необходимо постараться не сохранять списки дочерних процессов или унижаться через дерево процесса, например, путем помещения дочерних процессов в отдельную группу процесса, как предложено @Gilles.
В любом случае я подозреваю, что Ваш процесс daemonized был бы более обеспеченным созданием пула рабочего потока (который обязательно умирает наряду с его содержанием процесса), чем глубокое дерево sub-sub-sub-processes, который что-то где-нибудь затем должно очистить.
descendent_pids() {
pids=$(pgrep -P $1)
echo $pids
for pid in $pids; do
descendent_pids $pid
done
}
Есть еще вопрос правильности. Наивный анализ вывода pstree
проблематичен по нескольким причинам:
Если у вас установлен Python и psutil
пакет, вы можете использовать этот фрагмент для перечисления всех дочерних процессов:
pid=2235; python3 -c "import psutil
for c in psutil.Process($pid).children(True):
print(c.pid)"
(пакет psutil, например, установлен как зависимость от команды tracer
, которая доступна в Fedora / CentOS.)
В качестве альтернативы вы можете выполнить обход дерева процессов в ширину в оболочке bourne:
ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); \
done | tail -n +2 | tr " " "\n"
Для вычислений переходное закрытие pid, хвостовая часть может быть опущена.
Обратите внимание, что вышеупомянутая рекурсия не используется, а также выполняется в ksh-88.
В Linux можно исключить вызов pgrep
и вместо этого прочитать информацию из / proc
:
ps=2235; while [ "$ps" ]; do echo $ps ; \
ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done \
| tr " " "\n"' | tail -n +2
Это более эффективно, потому что мы сохраняем по одному fork / exec для каждого PID. и pgrep
выполняет некоторую дополнительную работу в каждом вызове.
Вот сценарий оболочки pgrep, который позволяет использовать pgrep и получать всех потомков одновременно.
~ / bin / pgrep_wrapper
:
#!/bin/bash
# the delimiter argument must be the first arg, otherwise it is ignored
delim=$'\n'
if [ "$1" == "-d" ]; then
delim=$2
shift 2
fi
pids=
newpids=$(pgrep "$@")
status=$?
if [ $status -ne 0 ]; then
exit $status
fi
while [ "$pids" != "$newpids" ]; do
pids=$newpids
newpids=$( { echo "$pids"; pgrep -P "$(echo -n "$pids" | tr -cs '[:digit:]' ',')"; } | sort -u )
done
if [ "$delim" != $'\n' ]; then
first=1
for pid in $pids; do
if [ $first -ne 1 ]; then
echo -n "$delim"
else
first=0
fi
echo -n "$pid"
done
else
echo "$pids"
fi
Вызвать так же, как и обычный pgrep, например pgrep_recursive -U $ USER java
, чтобы найти все процессы и подпроцессы Java из текущий пользователь.
Для этой версии Linux нужны только файлы /proc и ps. Он адаптирован из последней части отличного ответа @maxschlepzig . Эта версия считывает /proc непосредственно из оболочки, а не порождает подпроцесс -в цикле. Это немного быстрее и, возможно, немного элегантнее, как того требует заголовок этой темы.
#!/bin/dash
# Print all descendant pids of process pid $1
# adapted from https://unix.stackexchange.com/a/339071
ps=${1:-1}
while [ "$ps" ]; do
echo $ps
unset ps1 ps2
for p in $ps; do
read ps2 < /proc/$p/task/$p/children 2>/dev/null
ps1="$ps1 $ps2"
done
ps=$ps1
done | tr " " "\n" | tail -n +2
Я создал инструмент (Linux/procfs )под названием Procpath для запроса дерева процессов с использованием JSONPath.
Чтобы получить PID всех процессов-потомков, разделенных запятыми -не -корневого процесса (, т.е. для PID=1
используйте более простой запрос..stat.pid
)это:
$ procpath query -d, "..children[?(@.stat.pid == 15849)]..pid"
15849,16000,16039,16072,16109,16199
pstree -lp | grep -Po "(?<=\()\d+(?=\))"
– puchu 13.03.2018, 23:48