我有一个包含许多服务名称的文件,其中一些正在运行,其中一些不是。
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;
- 这给了我想要的结果。它足够有效吗?
谢谢!
答案 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_PID
和 ALL_PIDS
变量感兴趣的数据,因此您可以像这样打印结果:
if test -n "${ALL_PID}"
then
echo "${SERVICE}: ${ALL_PIDS}"
fi