You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编程解析GNU Screen会话列表 兼容含括号的特殊会话名

PHP解析GNU Screen会话列表的实现方案

需求是通过编程方式解析GNU Screen的会话列表,开发语言为PHP,也可参考其他语言的实现逻辑。最初尝试使用正则表达式解析,基本功能接近可用,但无法正确处理会话名称包含括号的边缘场景(该场景为GNU Screen官方支持的特性)。


初始正则解析方案

代码实现

<?php

declare(strict_types=1);
function screen_list_sessions(): array
{
    if (1) {
        // test code
        $raw = '
There are screens on:
        2064.screen with parenthesis in name ( this is stupid ) (10/02/2021 12:07:22 PM)        (Detached)
        1996.test session with spaces (10/02/2021 12:00:35 PM)        (Detached)
        1985.testSessionWithDuplicateName       (10/02/2021 12:00:23 PM)        (Detached)
        1974.testSessionWithDuplicateName       (10/02/2021 12:00:16 PM)        (Detached)
        1963.testSessionWithDuplicateName       (10/02/2021 12:00:09 PM)        (Detached)
        1871.testscreen (10/02/2021 11:59:23 AM)        (Detached)
6 Sockets in /run/screen/S-root.

';
    } else {
        $raw = shell_exec('screen -list');
    }
    $matches = [];
    $match_count = preg_match_all('/^\s+(?<session_id>\d+)\.(?<session_name>.*?)\((?<session_creation_date>[\s\S]+?)\)\s+\((?<session_state>[\s\S]+?)\)\s*?$/mu', $raw, $matches);
    $ret = [];
    for ($i = 0; $i < $match_count; ++$i) {
        $ret[] = [
            "session_id" => $matches["session_id"][$i],
            "session_name" => $matches['session_name'][$i],
            "session_creation_date" => $matches["session_creation_date"][$i],
            "session_state" => $matches["session_state"][$i]
        ];
    }
    return $ret;
}
var_export(screen_list_sessions());

运行输出

$ php test.php
array (
  0 =>
  array (
    'session_id' => '2064',
    'session_name' => 'screen with parenthesis in name ',
    'session_creation_date' => ' this is stupid ',
    'session_state' => '10/02/2021 12:07:22 PM)        (Detached',
  ),
  1 =>
  array (
    'session_id' => '1996',
    'session_name' => 'test session with spaces ',
    'session_creation_date' => '10/02/2021 12:00:35 PM',
    'session_state' => 'Detached',
  ),
  2 =>
  array (
    'session_id' => '1985',
    'session_name' => 'testSessionWithDuplicateName       ',
    'session_creation_date' => '10/02/2021 12:00:23 PM',
    'session_state' => 'Detached',
  ),
  3 =>
  array (
    'session_id' => '1974',
    'session_name' => 'testSessionWithDuplicateName       ',
    'session_creation_date' => '10/02/2021 12:00:16 PM',
    'session_state' => 'Detached',
  ),
  4 =>
  array (
    'session_id' => '1963',
    'session_name' => 'testSessionWithDuplicateName       ',
    'session_creation_date' => '10/02/2021 12:00:09 PM',
    'session_state' => 'Detached',
  ),
  5 =>
  array (
    'session_id' => '1871',
    'session_name' => 'testscreen ',
    'session_creation_date' => '10/02/2021 11:59:23 AM',
    'session_state' => 'Detached',
  ),
)

存在问题

第一条名称带括号的会话解析完全错位:名称中括号内的内容被错误识别为创建日期,状态字段混入了创建日期和多余的格式字符,不符合预期。


优化后的非正则解析方案

代码实现

<?php

declare(strict_types=1);
function screen_list_sessions(): array
{
    if (1) {
        // test code
        $raw = '
There are screens on:
        2064.screen with parenthesis in name ( this is stupid ) (10/02/2021 12:07:22 PM)        (Detached)
        1996.test session with spaces (10/02/2021 12:00:35 PM)        (Detached)
        1985.testSessionWithDuplicateName       (10/02/2021 12:00:23 PM)        (Detached)
        1974.testSessionWithDuplicateName       (10/02/2021 12:00:16 PM)        (Detached)
        1963.testSessionWithDuplicateName       (10/02/2021 12:00:09 PM)        (Detached)
        1871.testscreen (10/02/2021 11:59:23 AM)        (Detached)
6 Sockets in /run/screen/S-root.

';
    } else {
        $raw = shell_exec('screen -list');
    }
    $raw = implode("\n", array_filter(explode("\n", $raw), function (string $line): bool {
        // remove uninteresting lines; only lines that start with spaces are interesting..
        $trimmed = ltrim($line);
        if ($trimmed === $line) {
            return false;
        }
        if (strlen($trimmed) < 1) {
            // empty lines are also uninteresting
            return false;
        }
        // interesting line
        return true;
    }));
    $ret = [];
    $lines = explode("\n", $raw);
    foreach ($lines as $key => $line) {
        $current = [];
        $lastParStart = strrpos($line, '(');
        if ($lastParStart === false) {
            throw new \LogicException("line without \"(\": {$line}");
        }
        $lastParEnd = strrpos($line, ')');
        if ($lastParEnd === false) {
            throw new \LogicException("line without \")\": {$line}");
        }
        $current['session_state'] = substr($line, $lastParStart + strlen('('), $lastParEnd - $lastParStart - strlen(')'));
        $line = substr($line, 0, $lastParStart);
        $lastParStart = strrpos($line, '(');
        if ($lastParStart === false) {
            throw new \LogicException("line without 2nd \"(\": {$line}");
        }
        $lastParEnd = strrpos($line, ')');
        if ($lastParEnd === false) {
            throw new \LogicException("line without 2nd \")\": {$line}");
        }
        $current['session_creation_date'] = substr($line, $lastParStart + strlen('('), $lastParEnd - $lastParStart - strlen(')'));
        $line = substr($line, 0, $lastParStart - strlen("\t"));
        $dotPos = strpos($line, '.');
        if (false === $dotPos) {
            throw new \LogicException("");
        }
        $current['session_id'] = trim(substr($line, 0, $dotPos));
        // using trim() here probably means we won't 100% support sessions whose names starts or ends with space...
        $current['session_name'] = trim(substr($line, $dotPos + strlen(".")));
        // just put keys in pretty-ish order
        $current = [
            "session_id" => $current['session_id'],
            "session_name" => $current['session_name'],
            "session_state" => $current['session_state'],
            "session_creation_date" => $current['session_creation_date'],
        ];
        $ret[] = $current;
    }
    return $ret;
}
var_export(screen_list_sessions());

运行输出

array (
  0 =>
  array (
    'session_id' => '2064',
    'session_name' => 'screen with parenthesis in name ( this is stupid )',
    'session_state' => 'Detached',
    'session_creation_date' => '10/02/2021 12:07:22 PM',
  ),
  1 =>
  array (
    'session_id' => '1996',
    'session_name' => 'test session with spaces',
    'session_state' => 'Detached',
    'session_creation_date' => '10/02/2021 12:00:35 PM',
  ),
  2 =>
  array (
    'session_id' => '1985',
    'session_name' => 'testSessionWithDuplicateName',
    'session_state' => 'Detached',
    'session_creation_date' => '10/02/2021 12:00:23 PM',
  ),
  3 =>
  array (
    'session_id' => '1974',
    'session_name' => 'testSessionWithDuplicateName',
    'session_state' => 'Detached',
    'session_creation_date' => '10/02/2021 12:00:16 PM',
  ),
  4 =>
  array (
    'session_id' => '1963',
    'session_name' => 'testSessionWithDuplicateName',
    'session_state' => 'Detached',
    'session_creation_date' => '10/02/2021 12:00:09 PM',
  ),
  5 =>
  array (
    'session_id' => '1871',
    'session_name' => 'testscreen',
    'session_state' => 'Detached',
    'session_creation_date' => '10/02/2021 11:59:23 AM',
  ),
)

方案说明

该方案从右往左匹配括号提取状态和创建日期,规避了名称中括号的干扰,输出结果完全符合预期,可正确解析名称包含括号的会话。
当前存在的局限:由于会话名称提取时使用了trim()处理,暂时不支持解析名称首尾带空格的Screen会话。


内容的提问来源于stack exchange,提问作者hanshenrik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 21:36:03