Maneira portátil de encontrar todos os PIDs por cmdline

1

Eu quero encontrar o PID de todos os processos que foram executados por uma chamada cmdline que contém uma determinada string my_exec .

Por exemplo, com o macOS ou Ubuntu, abra um terminal e execute /bin/bash e, em seguida, em outro tipo de terminal ps all | grep '/bin/bash' . Você será solicitado com algo parecido com isto

  501  2995  2366   0  31  0  4290112   1424 -      Ss+  s000    0:00.01 /bin/bash --noediting -i
    0  2316  2274   0  31  0  4349520   6376 -      Ss   s007    0:00.02 login -pfl my_username /bin/bash -c exec -la bash /bin/bash
    0  2325  2274   0  31  0  4349520   6380 -      Ss   s008    0:00.02 login -pfl my_username /bin/bash -c exec -la bash /bin/bash
  501  8246  2333   0  31  0  4279872   1520 -      S+   s008    0:00.00 /bin/bash
  501  8255  8248   0  31  0  4267768    888 -      S+   s014    0:00.00 grep /bin/bash

A segunda coluna é o PID, então poderei reproduzi-lo com sed.

Com o Ubuntu, o formato da saída de ps all é um pouco diferente, portanto, deve-se usar chamadas sed diferentes, de qualquer maneira, é fácil lidar com isso.

O problema é que entre as várias distribuições Linux o formato da saída de ps pode ser completamente diferente. Por exemplo, este é o caso do Alpine Linux, para o qual eu nem sou capaz de obter a coluna contendo o cmdline.

O que posso fazer para ter um código portátil? Talvez examinando manualmente os arquivos /proc/<PID>/cmdline (talvez haja problema de permissões aqui)?

Este é o meu código até agora, por favor me ajude para a parte else.

if [ "$(uname)" == "Darwin" ]; then 
    pid=$(ps all|grep 'my_exec'|sed 's/^[[:space:]]*[a-z0-9]*//g'|sed 's/^[[:space:]]*\([0-9]*\)[^0-9].*//g');
    pid=$(echo $pid|xargs)
    IFS=' ' read -r -a array <<< "$pid"
else
    %portable code for various linux distros
fi
    
por Nisba 21.03.2018 / 19:10

2 respostas

2

Eu acredito que o problema é o uso da opção "all" - se você usar

Se a versão do ps suporta (busybox não), usando

 ps -o pid,command 

pode ser a maneira mais fácil de obter uma saída definida e fácil de passar

Se você usar

ps w

Isso será compatível com sistemas embarcados que também usam o Busybox, mas com menos funcionalidade.

    
por 21.03.2018 / 21:21
0

Acabei com este código, basicamente, ele considera todos os processos em /proc/ , procura o conteúdo de /proc/<PID>/cmdline e verifica se nessa sequência existe my_exec como substring.

Observe o uso de tr para analisar o conteúdo de cmdline para transformar uma string %code% -separated em uma string separada por espaço.

array=()
pids=$(find /proc -maxdepth 1 -name '*'|sed 's/^\/proc\(\/[-a-z_]*\)*//g'|tr '\n' ' '|xargs)
IFS=' ' read -r -a pid_array <<< "$pids"
for pid in "${pid_array[@]}"; do
    file="/proc/"$pid"/cmdline"
    if [ -f $file ]; then
        cmd=$(cat $file|tr '
array=()
pids=$(find /proc -maxdepth 1 -name '*'|sed 's/^\/proc\(\/[-a-z_]*\)*//g'|tr '\n' ' '|xargs)
IFS=' ' read -r -a pid_array <<< "$pids"
for pid in "${pid_array[@]}"; do
    file="/proc/"$pid"/cmdline"
    if [ -f $file ]; then
        cmd=$(cat $file|tr '%pre%' ' ')
        g=$(grep 'my_exec' <<< $cmd)
        if [ "${g: -1}" != " " ]; then                
            g=$g" "
        fi
        if [ "$cmd" == "$g" ] && [ -n "$cmd" ]; then
            echo '"'$cmd'"'", "'"'$g'"'
            array+=($pid)
        fi
    fi
done
' ' ') g=$(grep 'my_exec' <<< $cmd) if [ "${g: -1}" != " " ]; then g=$g" " fi if [ "$cmd" == "$g" ] && [ -n "$cmd" ]; then echo '"'$cmd'"'", "'"'$g'"' array+=($pid) fi fi done
    
por 22.03.2018 / 00:09

Tags