1

I want to find the PID of all processes which were run by a cmdline call which contains a certain string my_exec.

For instance, with macOS or Ubuntu, open a terminal and run /bin/bash, and then in another terminal type ps all | grep '/bin/bash'. You will be prompted with something like this

  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

The second column is the PID so I will be able to get it playing with sed.

With Ubuntu the format of the output of ps all slightly different, so one should use different sed calls, anyway it is easy to handle this.

The problem is that among the various Linux distros the format of the output of ps can be completely different. For instance this is the case of Alpine Linux, for which I am not even able to get the column containing the cmdline.

What can I do for having a portable code? Maybe examining manually the files /proc/<PID>/cmdline (maybe there are problem of permissions here)?

This is my code so far, please help me for the else part.

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

2 Answers 2

2

I believe the problem is your use of the "all" switch - if you use

If the version of ps supports it (busybox doesnt), using

 ps -o pid,command 

may be the easiest way to get a defined and easy to pass output

If you use

ps w

That will be compatible with embedded systems that use Busybox as well, but with less functionality.

1
  • I am trying this tomorrow, before you answered I continued working on a solution, I will post as an answer what I ended up with
    – Nisba
    Mar 21, 2018 at 23:05
0

I ended up with this code, basically it consider all processes in /proc/, looks for the content of /proc/<PID>/cmdline and check if in that string there is my_exec as substring.

Note the use of tr for parsing the content of cmdline to transform a \0-separated string into a space-separated string.

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 '\0' ' ')
        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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .