【问题标题】:Tcl parsing for a command output exits without giving any output对命令输出的 Tcl 解析退出而不给出任何输出
【发布时间】:2016-04-21 21:20:28
【问题描述】:

我正在尝试编写一个可以解析以下输出的脚本 -

dev1# show stats all

20:01:02-180 (stats) ID=1a2b3c
Work Stats           -- Now -- -------- Overall --------
                T1    T2   Total      T5     T6    Total
container        3      3    0          3     3       3
operatioms         3      3    0          3     3       3
docker         3      3    0          3     3       3
tcl         3      3    0          3     3       3
app         3      3    0          3     3       3
external         1      4    0 
intra         2      6    0 
incoming locks         8      6    0 
outgoing locks         4      3    0 
race-condition times    10      20      23
threads/usage           45      56      70

Power       2.3          10
Consumption 20.3%       29%

-----------------------------------------------------------------------
Separate Command
-----------------------------------------------------------------------



 dev1# show usage
    20:01:08-100
    OS:   48270 %
    Core:   4524 %
    User:   90 %

很遗憾,设备输出的格式不正确。

在浏览 tcl 博客时,我发现一个博客有以下代码 -

 set input [dev1 run "show stats"]
    array unset output
    array set output {}

    foreach line [split $input "\n"] {
        if {[regexp {^([^:]+?)\s*:\s*(\S+)\s*(\S+)?$} $line ]} {
            set key [string tolower $key 0 0]
            set output($key) $value
            if {[string length $units]} {
                set output(${key}Unit) $units

            }
        }
    }


    foreach {key value} [array get output] {
        puts [list $key $value]

    }

我无法让它工作。虽然,遵循博客步骤。有人可以指出一些提示来解决这个问题。我是论坛的新手,想了解更多信息。

预期输出

 stats {

    {time 20:01:02-180}
    {id 1a2b3c}
    {cmd stats}
    {Now 
        {T1 {container 3} {operatioms 3} {docker 3} {tcl 3} {app 3} {extrenal 3} {intra 2} {incoming_locks 8} {outgoing_locks 4} {race-condition_times 10} {threads/usage 45}}
        {T2 {container 3} {operatioms 3} {docker 3} {tcl 3} {app 3} {extrenal 4} {intra 6} {incoming_locks 6} {outgoing_locks 3} {race-condition_times 20} {threads/usage 56}}
        {Total {container 3} {operatioms 3} {docker 3} {tcl 3} {app 3} {extrenal 4} {intra 6} {incoming_locks 0} {outgoing_locks 0} {race-condition_times 23} {threads/usage 70}}
    }
    {Overall 
        {T5 {container 3} {operatioms 3} {docker 3} {tcl 3} {app 3} }
        {T6 {container 3} {operatioms 3} {docker 3} {tcl 3} {app 3} }
        {Total {container 3} {operatioms 3} {docker 3} {tcl 3} {app 3} }
    }
    {Power {current 2.3} {total 10}}
    {Consumptiomn {current 20.3%} {total 29%}}

    }


    -----------------------------------------------------------------------
    -----------------------------------------------------------------------


    usage {

    {time 20:01:08-100}
    {OS 48270%}
    {Core 4524%}
    {User 90%}

    }

谢谢

【问题讨论】:

  • 欢迎来到 StackOverflow!为了更好地回答您的问题,请编辑您的问题并指定您无法使用的内容。代码是否正在运行,是否解析了部分但不是全部的输出,是否解析不正确,等等。
  • 感谢 @buczek 的 cmets。我已经更新了问题。
  • 您应该查看您的正则表达式,它不会解析输入中的所有行。为相似的数据添加更多正则表达式并捕获所需的值
  • 您必须编写自己的解析器才能获得所需的输出。单个正则表达式将无法检索到这样的所有内容(除非您将其变得荒谬且难以理解)。

标签: tcl


【解决方案1】:

现在这是一种怪异的输出格式。

解析文本格式并不难,但生成输出格式需要一些工作。

这里有两个命令解析stats / usage 命令的输出并将数据收集到dict结构中:

proc parseStats txt {
    set data {}
    set keys1 {{Now T1} {Now T2} {Now Total} {Overall T5} {Overall T6} {Overall Total}}
    set keys2 {{Now T1} {Now T2} {Now Total}}
    foreach line [split [string trim $txt] \n] {
        switch -regexp -matchvar m $line {
            {^\s*(container)\M\s+(.*)} -
            {^\s*(operations)\M\s+(.*)} -
            {^\s*(docker)\M\s+(.*)} -
            {^\s*(tcl)\M\s+(.*)} -
            {^\s*(app)\M\s+(.*)} {
                lassign $m -> keystring values
                foreach key $keys1 val $values {
                    dict set data stats {*}$key $keystring $val
                }
            }
            {^\s*(external)\M\s+(.*)} -
            {^\s*(intra)\M\s+(.*)} -
            {^\s*(incoming locks)\M\s+(.*)} -
            {^\s*(outgoing locks)\M\s+(.*)} -
            {^\s*(race-condition times)\M\s+(.*)} -
            {^\s*(threads/usage)\M\s+(.*)} {
                lassign $m -> keystring values
                set keystring [string map {{ } _} $keystring]
                foreach key $keys2 val $values {
                    dict set data stats {*}$key $keystring $val
                }
            }
            {^\s*(Power)\M\s+(.*)} -
            {^\s*(Consumption)\M\s+(.*)} {
                lassign $m -> keystring values
                foreach lbl {current total} val $values {
                    dict set data stats $keystring $lbl $val
                }
            }
            ^\\d {
                dict set data stats time [lindex $line 0]
                dict set data stats cmd [string trim [lindex $line 1] ()]
                dict set data stats id [lindex [split [lindex $line 2] =] 1]
            }
        }
    }
    return $data
}

proc parseUsage txt {
    set data {}
    foreach line [split [string trim $txt] \n] {
        switch -regexp -matchvar m $line {
            {^\s*(OS)\M:\s+(.*)} -
            {^\s*(Core)\M:\s+(.*)} -
            {^\s*(User)\M:\s+(.*)} {
                lassign $m -> keystring values
                dict set data usage $keystring [join $values {}]
            }
            ^\\d {
                dict set data usage time $line
            }
        }
    }
    return $data
}

假设stats命令的输出在statsText变量中,usage命令的输出在usageText变量中,你可以构造这些字典结构(注意实际输出是white-space-packed:为了便于阅读,我添加了换行符和缩进)。

% set stats [parseStats $statsText]
% set stats
stats {
    time 20:01:02-180
    cmd stats
    id 1a2b3c
    Now {
        T1 {container 3 docker 3 tcl 3 app 3 external 1 intra 2 incoming_locks 8 outgoing_locks 4 race-condition_times 10 threads/usage 45}
        T2 {container 3 docker 3 tcl 3 app 3 external 4 intra 6 incoming_locks 6 outgoing_locks 3 race-condition_times 20 threads/usage 56}
        Total {container 0 docker 0 tcl 0 app 0 external 0 intra 0 incoming_locks 0 outgoing_locks 0 race-condition_times 23 threads/usage 70}
   }
    Overall {
        T5 {container 3 docker 3 tcl 3 app 3}
        T6 {container 3 docker 3 tcl 3 app 3}
        Total {container 3 docker 3 tcl 3 app 3}
    }
    Power {current 2.3 total 10}
    Consumption {current 20.3% total 29%}
}

% set usage [parseUsage $usageText]
% set usage
usage {
    time 20:01:08-100
    OS 48270%
    Core 4524%
    User 90%
}

如果可以,我强烈建议您使用此类字典,而不是问题中的输出格式。处理字典会容易得多。

如果您必须保持显示的输出格式,以下命令会将dict 结构转换为功能等效的字符串,如果不是空格等效的话:

proc prettyPrintDict dict {
    dict for {k v} $dict {
        if {[llength $v] == 1} {
            append res "{$k $v}\n"
        } else {
            append r [prettyPrintDict $v]
            append res "$k {\n$r}\n"
            set r {}
        }
    }
    return $res
}

% puts [prettyPrintDict [parseStats $statsText]]
% puts [prettyPrintDict [parseUsage $usageText]]

请注意,它依赖于所有值都是没有空格的单词。

文档:appenddictforeachiflassignprocputsreturnsetsplit、@3 987654332@

【讨论】:

  • 谢谢@Peter ....其中一个案例对我有用。对于另一组,我有不同的键和一些空格。有没有办法只从部分输入中删除空格?
  • @CentosNewbie:当然。 switch 选择器只是正则表达式,分组(括号)告诉使用lindex $m 1 提取什么。如果您发现自己很难做到这一点,请使用此新信息更新您的问题,我会看看我能做些什么。
  • @CentosNewbie:现在答案也更新了。
  • 谢谢@PeterLewerin .... 你的 tcl 程序就像一个魅力。我会发布一个更新的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-25
  • 2020-11-05
  • 2014-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
相关资源
最近更新 更多