有效地查找由服务启动的许多进程的PID

时间:2016-08-10 08:48:01

标签: bash centos7

我有一个包含许多服务名称的文件,其中一些正在运行,其中一些不是。

foo.service bar.service baz.service

我想找到一种有效的方法来获取服务启动的运行进程的PID(对于未运行的进程,0或-1或空结果有效)。

所需的输出示例:

foo.service:8484 bar.server: baz.service:9447

(bar.service isn不运行)。

到目前为止,我已成功完成以下任务:(1)

cat t.txt | xargs -I {} systemctl status {} | grep 'Main PID' | awk '{print $3}'

使用以下输出:

8484 9447

但我不能告诉每个PID属于哪个服务。

(我没有必要使用xargs,grep或awk ..只是寻找最有效的方式)。

到目前为止,我已成功完成以下任务:(2)

for f in `cat t.txt`; do
    v=`systemctl status $f | grep 'Main PID:'`;
    echo "$f:`echo $v | awk '{print \$3}'`";
done;

- 这给了我想要的结果。它足够有效吗?

谢谢!

3 个答案:

答案 0 :(得分:3)

我遇到了类似的问题,并寻求更精简的解决方案:

systemctl show --property MainPID --value $SERVICE

仅返回服务的PID,因此您的示例可以简化为

for f in `cat t.txt`; do
    echo "$f:`systemctl show --property MainPID --value $f`";
done

答案 1 :(得分:0)

你也可以这样做:

while read -r line; do
    statuspid="$(sudo service $line status | grep -oP '(?<=(process|pid)\s)[0-9]+')"

    appendline=""
    [[ -z $statuspid ]] && appendline="${line}:${statuspid}" || appendline="$line"

    "$appendline" >> services-pids.txt 
done < services.txt

要在变量中使用,您还可以使用关联数组:

declare -A servicearray=()

while read -r line; do
    statuspid="$(sudo service $line status | grep -oP '(?<=(process|pid)\s)[0-9]+')"

    [[ -z $statuspid ]] && servicearray[$line]="statuspid"
done < services.txt

# Echo output of array to command line
for i in "${!servicearray[@]}"; do  # Iterating over the keys of the associative array
  # Note key-value syntax
  echo "service: $i | pid: ${servicearray[$i]}"
done

提高效率

列出所有进程及其执行命令和PID。这可能会为每个命令提供多个PID,这可能很有用:

ps -eo pid,comm

所以:

psidcommand=$(ps -eo pid,comm)

while read -r line; do
    # Get all PIDs with the $line prefixed
    statuspids=$(echo $psidcommand | grep -oP '[0-9]+(?=\s$line)')

    # Note that ${statuspids// /,} replaces space with commas
    [[ -z $statuspids ]] && appendline="${line}:${statuspids// /,}" || appendline="$line"

    "$appendline" >> services-pids.txt 
done < services.txt

输出:

kworker:5,23,28,33,198,405,513,1247,21171,22004,23749,24055 

如果您确信您的文件具有该过程的完整名称,则可以替换:

grep -oP '[0-9]+(?=\s$line)'

grep -oP '[0-9]+(?=\s$line)$' # Note the extra "$" at the end of the regex

确保它完全匹配(在grep中没有尾随$,“mys”行与“mysql”匹配;在grep 尾随$,它不会,只会匹配“mysql”)。

答案 2 :(得分:0)

根据 Yorik.sar 的回答,您首先要像这样获得服务器的 MainPID

for SERVICE in ...<service names>...
do
    MAIN_PID=`systemctl show --property MainPID --value $SERVICE`
    if test ${MAIN_PID} != 0
    than
        ALL_PIDS=`pgrep -g $MAIN_PID`
        ...
    fi
done

因此,使用 systemctl 可为您提供由守护程序控制的主进程的 PID。然后 pgrep 为您提供守护程序以及守护程序启动的所有进程的 PID 列表。

注意:如果进程是用户进程,则您必须在 --user 命令行上使用 systemctl 才能使事情发挥作用:

MAIN_PID=`systemctl --user show --property MainPID --value $SERVICE`

现在您有了对 MAIN_PIDALL_PIDS 变量感兴趣的数据,因此您可以像这样打印结果:

if test -n "${ALL_PID}"
then
    echo "${SERVICE}: ${ALL_PIDS}"
fi