Bash:获取守护进程屏幕会话的PID

问题描述 投票:8回答:7

如果我作为守护进程启动GNU屏幕会话,我将如何以编程方式检索其PID?我不知道screen -ls的输出是多么一致,所以我想知道如何使用bash的常量之一,$$$!或更好的选择。

我正在用screen -dmS screenname开始屏幕。

如何在开始屏幕会话之前或之后立即获得屏幕的PID?

bash gnu-screen
7个回答
14
投票

这显示了名为nameofscreen的屏幕的pid:

$ screen -ls
There are screens on:
    19898.otherscreen   (07/03/2012 05:50:45 PM)    (Detached)
    19841.nameofscreen  (07/03/2012 05:50:23 PM)    (Detached)
2 Sockets in /var/run/screen/S-sarnold.

$ screen -ls | awk '/\.nameofscreen\t/ {print strtonum($1)}'
19841
$ 

3
投票

您可以使用:

screen -DmS nameofscreen

它不会分叉守护程序进程,让您知道pid。

如果已使用相同名称启动了两个屏幕会话,则解析屏幕-ls的输出可能不可靠。另一种方法是不让屏幕会话分叉一个进程并自己将它放在后台:

例如,使用现有的初始屏幕会话:

fess@hostname-1065% screen -ls
There is a screen on:
        19180.nameofscreen    (01/15/2013 10:11:02 AM)        (Detached)

使用-D -m而不是-d -m创建一个屏幕,它不会分叉新进程。把它放在后台并获得它的pid。 (使用posix shell语义)

fess@hostname-1066% screen -DmS nameofscreen & 
[3] 19431
fess@hostname-1067% pid=$! 

现在有两个屏幕都有相同的名称:

fess@hostname-1068% screen -ls
There are screens on:
        19431.nameofscreen    (01/15/2013 10:53:31 AM)        (Detached)
        19180.nameofscreen    (01/15/2013 10:11:02 AM)        (Detached)

但我们知道不同之处:

fess@hostname-1069% echo $pid
19431

我们可以准确地要求它退出:

fess@hostname-1070% screen -S $pid.nameofscreen -X quit
[3]  - done       screen -DmS nameofscreen

现在只有原来的一个:

fess@hostname-1071% screen -ls 
There is a screen on:
        19180.nameofscreen    (01/15/2013 10:11:02 AM)        (Detached)

3
投票

您可以在此处获取屏幕会话的PID,如下所示:

$ screen -ls
There are screens on:
        1934.foo_Server         (01/25/15 15:26:01)     (Detached)
        1876.foo_Webserver      (01/25/15 15:25:37)     (Detached)
        1814.foo_Monitor        (01/25/15 15:25:13)     (Detached)
3 Sockets in /var/run/screen/S-ubuntu.

让我们假设您希望在foo_Monitor屏幕会话中在Bash中运行程序的PID。使用foo_Monitor屏幕会话的PID通过在PPID(父PID)中搜索已知的PID来获取在其中运行的bash会话的PID:

$ ps -el | grep 1814 | grep bash
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  1815  1814  0  80   0 -  5520 wait   pts/1    00:00:00 bash

现在只获得bash会话的PID:

$ ps -el | grep 1814 | grep bash | awk '{print $4}'
1815

现在我们想要具有该PID的过程。只需嵌套命令,这次使用-v上的grep bash标志来获取非bash的进程:

echo $(ps -el | grep $(ps -el | grep 1814 | grep bash | awk '{print $4}') | grep -v bash | awk '{print $4}')
23869

只需用实际PID或屏幕会话替换1814:

echo $(ps -el | grep $(ps -el | grep SCREEN_SESSION_PID | grep bash | awk '{print $4}') | grep -v bash | awk '{print $4}')

2
投票

我怀疑你真的希望程序的PID在屏幕内运行,这似乎不容易获得。 (并不是一个定义明确的问题,因为单个屏幕进程可以管理多个孩子 - 这是关于屏幕的一件好事!)

您可以使用pgrep查找PPID为屏幕PID的进程。或者做这样的事情:

rm mypidfile
screen -dmS blah sh -c 'echo $$ > mypidfile ; exec sh'
# the write to mypidfile is happening in the background, so wait it to show up
while [ ! -s mypidfile ]; do sleep 1; done
pid=`cat mypidfile`
# $pid is now the PID of the shell that was exec'ed inside screen

0
投票

另一种方法是使用screen的-Q参数来查询会话:

screen -S nameofscreen -Q echo '$PID'

请注意,这也会在屏幕会话中显示PID作为通知。


0
投票

完成sarnold的答案:

$ screen -ls
There are screens on:
    19898.otherscreen   (07/03/2012 05:50:45 PM)    (Detached)
    19841.nameofscreen  (07/03/2012 05:50:23 PM)    (Detached)
2 Sockets in /var/run/screen/S-sarnold.

$ screen -ls | awk '/\.nameofscreen\t/ {print strtonum($1)}'
19841

...使用此PID作为PPID获取进程的PID,如下所示:

$ ps --ppid 19841 -o pid=
19842

0
投票

这个答案的灵感来自@sarnold。

让我添加一种获取所有屏幕PID的方法:

screen -ls | awk '/[0-9]{1,}\./ {print strtonum($1)}'

由于0-299是旧内核中守护程序的PID,因此可以将{1,}更改为{3,}

您可以通过以下方式对每个进程进行操作,例如退出它们。

pidList=(screen -ls | awk '/[0-9]{3,}\./ {print strtonum($1)}')
for pid in ${pidList[@]};
do
    screen -X -S $pid quit
done

你也可以用screen -X -S $pid stuff 'command\n'做一些其他的事情。

© www.soinside.com 2019 - 2024. All rights reserved.