Bash: 获取守护化 screen 会话的 PID

14
如果我作为一个守护进程启动GNU screen会话,如何以编程方式检索其PID?我不知道screen -ls的输出有多一致,因此我想知道如何使用bash的一个常量$$、$!或更好的替代方法来完成这项工作。我是用screen -dmS screenname启动screen的。在启动屏幕会话之前或之后立即获取屏幕的PID应该怎么做呢?

screen -ls 有什么问题吗? - sarnold
为什么你不能用screen -ls的脚本来完成呢? - sarnold
8个回答

19

这将展示名为nameofscreen的屏幕的进程ID:

$ 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
$ 

8

您可以使用:

screen -DmS nameofscreen

该方法不会分叉出一个守护进程,让您能够知道pid。

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

例如,对于现有的初始screen会话:

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

使用-D -m选项创建一个屏幕,而不是-d -m选项,这不会fork一个新进程。将其放在后台并获取其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 screen会话中运行的Bash程序的PID。使用foo_Monitor screen会话的PID来查找已知PID的PPID(父进程ID),以获取其中运行的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 会话的进程ID(PID):
$ ps -el | grep 1814 | grep bash | awk '{print $4}'
1815

现在我们想要使用那个 PID 的进程。只需要嵌套命令,并且这次在 grep bash 命令中使用 -v 标志以获取不是 bash 进程的进程:

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

只需将1814替换为您的屏幕会话的真实PID:

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

3
这个答案是受@sarnold启发而来的。
让我添加一种获取所有屏幕进程ID的方法:
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' 来执行一些其他操作。


2
我猜测你想要在screen中运行的程序的PID,这似乎不容易得到。(而且这并不是一个明确的问题,因为单个screen进程可以管理多个子进程——这就是screen的优点之一!)
你可以使用pgrep查找其PPID为screen 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

1
如果您有子进程的 PID $pid,则 ps -p $pid -o ppid= 将显示其父进程的 PID。 - Alan Curry

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
另一种方法是使用screen的-Q参数来查询会话:
screen -S nameofscreen -Q echo '$PID'

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

0

第一个答案对我没用。相反,我用了这个:

screen -ls | grep -oE "[0-9]+\.screen_name" | sed -e "s/\..*$//g"

grep -oE 只返回与正则表达式匹配的内容,该正则表达式至少匹配一个数字、一个字面点和 screen_name。例如,这可能会输出 784.screen_name(如果 pid 是 784)。然后,使用 sed 命令删除第一个点之后到字符串结尾的所有内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接