【问题标题】:Bash: Getting PID of daemonized screen sessionBash:获取守护进程屏幕会话的 PID
【发布时间】:2012-07-03 23:59:40
【问题描述】:

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

我以screen -dmS screenname 开始屏幕。

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

【问题讨论】:

  • screen -ls 有什么问题?
  • .. 你为什么不能用 screen -ls 的脚本来做呢?

标签: bash gnu-screen


【解决方案1】:

这显示了一个名为 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
$ 

【讨论】:

    【解决方案2】:

    你可以使用:

    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)
    

    【讨论】:

      【解决方案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 通过搜索已知 PID 的 PPID(父 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 的进程。只需嵌套命令,这次使用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}')
      

      【讨论】:

        【解决方案4】:

        我怀疑你真的想要在屏幕内运行的程序的 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
        

        【讨论】:

        • 如果 $pid 中有孩子的 PID,ps -p $pid -o ppid= 将显示父母的 PID。
        【解决方案5】:

        这个答案的灵感来自@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' 做一些其他事情。

        【讨论】:

          【解决方案6】:

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

          screen -S nameofscreen -Q echo '$PID'
          

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

          【讨论】:

            【解决方案7】:

            完成萨诺德的回答:

            $ 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 的进程的 PID 作为 PPID,如下所示:

            $ ps --ppid 19841 -o pid=
            19842
            

            【讨论】:

              【解决方案8】:

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

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2014-12-11
                • 2023-03-08
                • 2016-05-08
                • 2014-10-10
                • 2015-10-11
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多