通过命令行查找所有 PID 的便捷方法

通过命令行查找所有 PID 的便捷方法

我想找到由包含特定字符串的命令行调用运行的所有进程的 PID 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 就是这种情况,我甚至无法获取包含命令行的列。

我该怎么做才能获得可移植的代码?也许手动检查文件/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

我相信问题在于你使用了“全部”开关 - 如果你使用

如果 ps 版本支持它(busybox 不支持),使用

 ps -o pid,command 

可能是获得明确且易于传递的输出的最简单方法

如果你使用

ps w

这将与使用 Busybox 的嵌入式系统兼容,但功能较少。

答案2

我最终得到了这个代码,基本上它考虑了中的所有过程/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 "${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

相关内容