12

如果我将 GNU 屏幕会话作为守护进程启动,我将如何以编程方式检索其 PID?我不知道输出的一致性如何 screen -ls,所以我想知道如何使用 bash 的常量之一或更好的替代方法来做到这$$一点$!

我正在使用 启动屏幕screen -dmS screenname

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

4

8 回答 8

17

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

$ 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
$ 
于 2012-07-04T00:58:52.543 回答
5

您可以使用:

screen -DmS nameofscreen

它不会派生一个让您知道 pid 的守护进程。

如果两个屏幕会话已以相同的名称启动,则解析 screen -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)
于 2013-01-15T19:12:38.447 回答
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屏幕会话的 PIDbash通过搜索已知 PID 的 PPID(父 PID)来获取在其中运行的会话的 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标志 ongrep bash来获取不是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}')
于 2015-02-08T14:47:00.533 回答
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
于 2012-07-04T01:31:50.287 回答
2

这个答案的灵感来自@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'.

于 2019-03-09T10:13:31.377 回答
0

完成萨诺德的回答:

$ 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
于 2018-02-08T04:03:00.593 回答
0

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

screen -S nameofscreen -Q echo '$PID'

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

于 2017-11-17T00:40:46.150 回答
0

第一个答案对我不起作用。相反,我使用了这个:

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

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

于 2020-08-09T16:52:34.940 回答