我有一个包含许多 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;
-- 这给了我想要的结果。效率够高吗?
我遇到了类似的问题并找到了更精简的解决方案:
systemctl show --property MainPID --value $SERVICE
仅返回服务的 PID,因此您的示例可以简化为
for f in `cat t.txt`; do
echo "$f:`systemctl show --property MainPID --value $f`";
done
你也可以这样做:
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”)。
在 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