Elegantemente obter lista de processos descendentes

22

Gostaria de obter uma lista de todos os processos descendentes (por exemplo, filhos, netos, etc.) de $pid . Esta é a maneira mais simples que eu criei:

pstree -p $pid | tr "\n" " " |sed "s/[^0-9]/ /g" |sed "s/\s\s*/ /g"

Existe algum comando, ou alguma maneira mais simples de obter a lista completa de processos descendentes todos ?

    
por STenyaK 12.03.2013 / 14:58

6 respostas

13

O seguinte é um pouco mais simples e tem a vantagem adicional de ignorar números nos nomes dos comandos:

pstree -p $pid | grep -o '([0-9]\+)' | grep -o '[0-9]\+'

Ou com o Perl:

pstree -p $pid | perl -ne 'print "$1\n" while /\((\d+)\)/g'

Estamos procurando números entre parênteses para que, por exemplo, não damos 2 como um processo filho quando nos deparamos com gif2png(3012) . Mas se o nome do comando contiver um número entre parênteses, todas as apostas serão desativadas. Há apenas até agora o processamento de texto pode levá-lo.

Então, também acho que os grupos de processos são o caminho a percorrer. Se você quiser que um processo seja executado em seu próprio grupo de processos, você pode usar a ferramenta 'pgrphack' do pacote Debian 'daemontools':

pgrphack my_command args

Ou você pode voltar para o Perl:

perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args

A única ressalva aqui é que os grupos de processos não aninham, portanto, se algum processo estiver criando seus próprios grupos de processos, seus subprocessos não estarão mais no grupo que você criou.

    
por 14.07.2013 / 21:01
6
descendent_pids() {
    pids=$(pgrep -P $1)
    echo $pids
    for pid in $pids; do
        descendent_pids $pid
    done
}
    
por 30.07.2016 / 01:27
1

A versão mais curta que encontrei também lida corretamente com comandos como pop3d :

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

Ele lida incorretamente se você tiver comandos com nomes estranhos como: my(23)prog .

    
por 14.07.2013 / 23:05
1

Há também a questão da correção. Analisar de forma inédita a saída de pstree é problemático por diversos motivos:

  • pstree exibe os PIDs e os ids dos encadeamentos (os nomes são mostrados nas chaves)
  • um nome de comando pode conter chaves, números entre parênteses que tornam a análise confiável impossível

Se você tiver o Python e o pacote psutil instalado, poderá usar este snippet para listar todos os processos descendentes:

pid=2235; python3 -c "import psutil
for c in psutil.Process($pid).children(True):
  print(c.pid)"

(O pacote psutil é instalado, por exemplo, como uma dependência do comando tracer que está disponível no Fedora / CentOS.)

Como alternativa, você pode fazer uma travessia em largura da árvore de processos em uma casca de bourne:

ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); \
  done | tail -n +2 | tr " " "\n"

Para calcular o fechamento transitivo de um pid, a parte da cauda pode ser omitida.

Note que o acima não usa recursão e também é executado em ksh-88.

No Linux, pode-se eliminar a chamada pgrep e ler as informações de /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

Isso é mais eficiente porque salvamos um fork / exec para cada PID e pgrep faz algum trabalho adicional em cada chamada.

    
por 21.01.2017 / 10:03
0

Em cada um dos seus dois (aparentemente muito artificiais) casos de uso, por que você quer matar alguns sub-processos do infeliz processo? Como você sabe melhor do que um processo em que seus filhos devem viver ou morrer? Isso parece um design ruim para mim; um processo deve limpar depois de si mesmo.

Se você realmente conhece melhor, então você deve estar forking esses subprocessos, e o 'processo daemonized' é aparentemente muito burro para ser confiável para fork(2) .

Você deve evitar manter listas de processos filhos ou arrastar-se pela árvore de processos, por exemplo, colocando os processos filhos em um grupo de processos separado, como sugerido por @Gilles.

Em qualquer caso, suspeito que seu processo de daemon seria melhor criar um pool de threads de trabalho (que necessariamente morre junto com seu processo de contenção) do que uma deep tree de sub-sub-subprocessos, algo que em algum lugar tem para limpar.

    
por 14.07.2013 / 17:54
0

Aqui está um script de wrapper do pgrep que permite usar o pgrep e obter todos os descendentes ao mesmo tempo.

~/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

Invoque da mesma forma que invocaria o pgrep normal, como pgrep_recursive -U $USER java , para localizar todos os processos e subprocessos Java do usuário atual.

    
por 10.04.2017 / 03:01

Tags