高效查找服务启动的多个进程的PID

问题描述 投票:0回答:3

我有一个包含许多 service 名称的文件,其中一些正在运行,其中一些没有。

foo.service
bar.service
baz.service

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

所需的输出示例:

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

bar.service
未运行)。

到目前为止,我已成功执行以下操作:(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;

-- 这给了我想要的结果。效率够高吗?

bash centos7
3个回答
32
投票

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

systemctl show --property MainPID --value $SERVICE

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

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

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”)。


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_PID
ALL_PIDS
变量感兴趣的数据,因此您可以像这样打印结果:

if test -n "${ALL_PID}"
then
    echo "${SERVICE}: ${ALL_PIDS}"
fi
© www.soinside.com 2019 - 2024. All rights reserved.