Портативный способ найти все PID по cmdline

329
Nisba

Я хочу найти PID всех процессов, которые были запущены вызовом cmdline, который содержит определенную строку my_exec.

Например, в macOS или Ubuntu, откройте терминал и запустите /bin/bash, а затем в терминале другого типа ps all | grep '/bin/bash'. Вам будет предложено что-то вроде этого

 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 

Второй столбец - это PID, поэтому я смогу поиграть в него с помощью sed.

С Ubuntu формат вывода ps allнемного отличается, поэтому следует использовать разные вызовы sed, в любом случае с этим легко справиться.

Проблема в том, что среди различных дистрибутивов Linux формат вывода psможет быть совершенно разным. Например, это случай Alpine Linux, для которого я даже не могу получить столбец, содержащий cmdline.

Что я могу сделать, чтобы иметь переносимый код? Может быть, вручную проверять файлы /proc/<PID>/cmdline(возможно, здесь есть проблема с разрешениями)?

Это мой код, пожалуйста, помогите мне для остальной части.

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

2 ответа на вопрос

2
davidgo

Я считаю, что проблема в том, что вы используете переключатель «все» - если вы используете

Если версия PS поддерживает это (busybox нет), используя

 ps -o pid,command 

может быть самым простым способом получить определенный и простой для передачи вывод

Если вы используете

ps w 

Это будет совместимо со встроенными системами, которые также используют Busybox, но с меньшей функциональностью.

Я пробую это завтра, прежде чем вы ответите, я продолжил работу над решением, я опубликую в качестве ответа, что я закончил Nisba 6 лет назад 0
0
Nisba

Я закончил с этим кодом, в основном он рассматривает все процессы /proc/, ищет содержимое /proc/<PID>/cmdlineи проверяет, есть ли в этой строке my_execподстрока.

Обратите внимание на использование trдля анализа содержимого cmdlineдля преобразования \0строки, разделенной пробелами, в строку, разделенную пробелами.

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 "$"; do file="/proc/"$pid"/cmdline" if [ -f $file ]; then cmd=$(cat $file|tr '\0' ' ') g=$(grep 'my_exec' <<< $cmd) if [ "$" != " " ]; then  g=$g" " fi if [ "$cmd" == "$g" ] && [ -n "$cmd" ]; then echo '"'$cmd'"'", "'"'$g'"' array+=($pid) fi fi done 

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