我想找到由包含特定字符串的命令行调用运行的所有进程的 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