Изящно получите список порожденных процессов

Изменение Python по умолчанию (или Perl, и т.д.) на ОС является действительно плохой идеей. Этот интерпретатор является на самом деле частью ОС и могут быть другие компоненты ОС, которые записаны конкретно для работы с той версией интерпретатора.

Например, на Redhat вкусный инструмент, который выполняет обновления системного программного обеспечения, является приложением Python. Вы действительно не хотите повреждать это. Такие приложения могут зависеть от определенного, возможно, нестандартного, модули Python, устанавливаемые, который не может иметь версия, которую Вы установили. Например, на Ubuntu я полагаю, что некоторые встроенные инструменты OS, записанные в Python, используют ORM, названный Storm, который не является частью библиотеки стандарта Python. Ваша чистая установка Python 2.7 имеет определенную ожидаемую версию модуля Storm установленной? Это имеет какую-либо версию Storm? Нет? Затем Вы только что повредили блок своей ОС.

Правильный способ сделать это - установка Ваша предпочтительная версия Python и настроило Вашу учетную запись пользователя для использования его путем установки .bash_profile, пути и такого. Вы могли бы также хотеть изучить virtualenv модуль для Python.

23
06.10.2015, 10:21
8 ответов

Следующее несколько более просто, и имеет добавленное преимущество игнорирования чисел на названия команды:

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

Единственный протест здесь состоит в том, что группы процесса не вкладывают, поэтому если некоторый процесс создаст свои собственные группы процесса, то его подпроцессы больше не будут в группе, которую Вы создали.

15
27.01.2020, 19:42
  • 1
    произвольны, и можете, или может не использовать сами группы процесса (я ничего не могу принять). Однако Ваш ответ появляется самое близкое к тому, какое землетрясение быть достижимым в Linux, таким образом, я приму его.Спасибо. –  STenyaK 17.07.2013, 14:57
  • 2
    Это было очень полезно! –  Michal Gallovic 11.02.2016, 22:43
  • 3
    , каналы pstree будут также включать идентификаторы потока, т.е. идентификаторы потоков, которые запустил $pid. –  maxschlepzig 21.01.2017, 11:05
  • 4
    Можно использовать единственный grep: pstree -lp | grep -Po "(?<=\()\d+(?=\))" –  puchu 13.03.2018, 23:48

Самая короткая версия я нашел, что также имеет дело правильно с командами как pop3d:

pstree -p $pid | perl -ne 's/\((\d+)\)/print " $1"/ge'

Это имеет дело неправильно, если у Вас есть команды, которые имеют странные имена как: my(23)prog.

1
27.01.2020, 19:42
  • 1
    Это не работает на команды, которые выполняют некоторый поток (потому что pstree печатает те идентификаторы, также). –  maxschlepzig 21.01.2017, 11:08

В каждом из Ваших двух (по-видимому очень искусственных) вариантов использования, почему Вы хотите уничтожить подпроцессы некоторого неудачного процесса? Как Вы знаете лучше, чем процесс, когда его дети должны жить или умереть? Это походит на плохой дизайн мне; процесс должен вымыться после себя.

Если Вы действительно знаете лучше, то необходимо разветвлять эти подпроцессы, и 'daemonized процесс' является по-видимому слишком немым, чтобы доверяться к fork(2).

Необходимо постараться не сохранять списки дочерних процессов или унижаться через дерево процесса, например, путем помещения дочерних процессов в отдельную группу процесса, как предложено @Gilles.

В любом случае я подозреваю, что Ваш процесс daemonized был бы более обеспеченным созданием пула рабочего потока (который обязательно умирает наряду с его содержанием процесса), чем глубокое дерево sub-sub-sub-processes, который что-то где-нибудь затем должно очистить.

0
27.01.2020, 19:42
  • 1
    Оба варианта использования используются в непрерывной интеграции/тестовой среде, таким образом, они должны иметь дело с возможностью ошибки, существующей в дочернем процессе/es. Эта ошибка может проявиться как неспособность правильно завершить работу себя или их детей, таким образом, мне нужен способ гарантировать, что я могу закрыть их всех в худшем случае. дочерние процессы –  STenyaK 17.07.2013, 14:55
  • 2
    В этом случае я с @Gilles и @Jander; группы процесса являются лучшим способом. –  AnotherSmellyGeek 13.09.2013, 16:58
descendent_pids() {
    pids=$(pgrep -P $1)
    echo $pids
    for pid in $pids; do
        descendent_pids $pid
    done
}
7
27.01.2020, 19:42

Есть еще вопрос правильности. Наивный анализ вывода pstree проблематичен по нескольким причинам:

  • pstree отображает идентификаторы PID и идентификаторы потоков (имена показаны в фигурных скобках)
  • имя команды может содержат фигурные скобки, числа в скобках, которые делают невозможным надежный синтаксический анализ

Если у вас установлен 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 выполняет некоторую дополнительную работу в каждом вызове.

1
27.01.2020, 19:42

Вот сценарий оболочки 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 из текущий пользователь.

0
27.01.2020, 19:42

Для этой версии 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
1
27.01.2020, 19:42

Я создал инструмент (Linux/procfs )под названием Procpath для запроса дерева процессов с использованием JSONPath.

Чтобы получить PID всех процессов-потомков, разделенных запятыми -не -корневого процесса (, т.е. для PID=1используйте более простой запрос..stat.pid)это:

$ procpath query -d, "..children[?(@.stat.pid == 15849)]..pid"
15849,16000,16039,16072,16109,16199
0
05.09.2020, 16:09

Теги

Похожие вопросы