【问题标题】:one liner to extract data block by block一根线逐块提取数据
【发布时间】:2024-05-01 20:45:02
【问题描述】:

我总是处理由以下格式的许多数据块组成的数据文件:

*name* attr (
        VALID (
                late_lead_up xxx ar uclk reff xxx slope xxx
                late_lead_dn xxx af uclk reff xxx slope xxx
                early_trail_up xxx af uclk reff xxx slope xxx
                early_trail_dn xxx ar uclk reff xxx slope xxx
              )
        CEXT xxx
        CREF xxx
        REFF xxx
        QUALIFIED_CLOCK
)

无论如何我可以从命令行中提取我有兴趣使用单行符的“名称”吗?

【问题讨论】:

  • 你知道block有多少行吗?
  • 行数不固定
  • name 及其右括号是否出现在行首?行首是否还有其他内容?
  • no name 和右括号在 ^ 位置
  • 查看我的更新以获得 perl 解决方案,该解决方案考虑了“QUALIFIED_CLOCK”要求 - 不是最易读的单行代码,尽管它可以转换为脚本。

标签: command-line text


【解决方案1】:

将此文件用于演示目的:

of_interest attr (
    1:VALID (
        1:late_lead_up xxx ar uclk reff xxx slope xxx
        1:late_lead_dn xxx af uclk reff xxx slope xxx
        1:early_trail_up xxx af uclk reff xxx slope xxx
        1:early_trail_dn xxx ar uclk reff xxx slope xxx
    1:)
    1:CEXT xxx
    1:CREF xxx
    1:REFF xxx
    1:QUALIFIED_CLOCK
)

boring attr (
    2:VALID (
        2:late_lead_up xxx ar uclk reff xxx slope xxx
        2:late_lead_dn xxx af uclk reff xxx slope xxx
        2:early_trail_up xxx af uclk reff xxx slope xxx
        2:early_trail_dn xxx ar uclk reff xxx slope xxx
    2:)
    2:CEXT xxx
    2:CREF xxx
    2:REFF xxx
    2:QUALIFIED_CLOCK
)

of_interest attr (
    3:VALID (
        3:late_lead_up xxx ar uclk reff xxx slope xxx
        3:late_lead_dn xxx af uclk reff xxx slope xxx
        3:early_trail_up xxx af uclk reff xxx slope xxx
        3:early_trail_dn xxx ar uclk reff xxx slope xxx
    3:)
    3:CEXT xxx
    3:CREF xxx
    3:REFF xxx
    3:QUALIFIED_CLOCK
)

这一行(为便于阅读而拆分):

awk '
    BEGIN               {s=0}
    /^of_interest /     {s=1}
    /^)$/               {if (s==1) {print};s=0}
                        {if (s==1) print}'

或最低字符版本:

awk 'BEGIN{s=0}/^of_interest /{s=1}/^)$/{if(s==1){print};s=0}{if(s==1)print}'

给你:

of_interest attr (
    1:VALID (
        1:late_lead_up xxx ar uclk reff xxx slope xxx
        1:late_lead_dn xxx af uclk reff xxx slope xxx
        1:early_trail_up xxx af uclk reff xxx slope xxx
        1:early_trail_dn xxx ar uclk reff xxx slope xxx
    1:)
    1:CEXT xxx
    1:CREF xxx
    1:REFF xxx
    1:QUALIFIED_CLOCK
)
of_interest attr (
    3:VALID (
        3:late_lead_up xxx ar uclk reff xxx slope xxx
        3:late_lead_dn xxx af uclk reff xxx slope xxx
        3:early_trail_up xxx af uclk reff xxx slope xxx
        3:early_trail_dn xxx ar uclk reff xxx slope xxx
    3:)
    3:CEXT xxx
    3:CREF xxx
    3:REFF xxx
    3:QUALIFIED_CLOCK
)

我相信这就是你所追求的。

它基本上是一个简单的状态机,当它找到所需的块开始时打开打印,并在找到该块的结尾时关闭它。

更新:这是一个 perl 单行代码,可以满足您的qualified_clock 要求。享受:-)

perl -e '$s=1;while(<STDIN>){if(/^of_interest /){$s=1;$f=0;$x="";}if(($s==1)&&/QUALIFIED_CLOCK/){$f=1;}if(/^\)$/){if($s==1){$x.=$_;}if($f==1){print$x;}$s=0;next;}if($s==1){$x.=$_;}}'

【讨论】:

  • 如果有些数据块有 QUALIFIED_CLOCK 而有些没有,我想提取所有带有 QUALIFIED_CLOCK 的块?
  • 那么你需要存储这些行而不是打印它们,在启动块时清除一个标志,如果找到 QUALIFIED_CLOCK 则设置它,当你找到块结束时,如果标志已设置。
  • 如果有更多的需求变化,我会选择转向基于 Python/Perl 的解决方案,但它不会是任何语言的可读单行代码 :-)
【解决方案2】:

Pax'sone更少的字符和更简单的解决方案

perl -ne '/^of_interest /../^\)/ and print'

awk '/^of_interest /,/^\)/{print}'

sed -n '/^of_interest /,/^)/p'

【讨论】:

    【解决方案3】:

    如果你的块总是以'*name* attr ('开头并且总是以')'结尾并且没有前导空格,你可以尝试(假设foo是块名称,data.txt是文件解析):

    awk '/ attr \($/ {if($1==n)b=1}  {if(b)print}  /^\)$/ {b=0}' n=foo data.txt
    

    【讨论】:

      【解决方案4】:

      好吧,你给它贴上了 Perl 的标签,下面是我在 Perl 中的做法:

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      
      die "usage: $0 name datafile\n    or cat datafile | $0 name\n" 
          unless @ARGV > 0;
      
      my $name = shift;
      my $re   = qr/\A$name attr/; 
      
      my $rec = '';
      while (my $line = <>) {
          $rec .= $line;
          next unless $line =~ /^\)/;
          print $rec if $rec =~ /$re/;
          $rec = '';
      }
      

      你可以把它变成这样的单线

      perl -ne '$a.=$_;next unless/^\)/;print$a if$a=~/^name/;$a=""' datafile
      

      但我更喜欢脚本。请记住将 name 替换为记录的名称。

      【讨论】:

        【解决方案5】:

        我在您的 cmets 中看到另一个答案,您还想在块中搜索类似“QUALIFIED_CLOCK”的字符串。

        在这种情况下,如果你的数据块用空行分隔,你可以使用 Perl 的段落模式分块读取并打印出你感兴趣的部分。例如: p>

        perl -00 -ne 'print if /^block_name/ and /QUALIFIED_CLOCK/' file.txt
        

        这也可以通过设置 RS 在 awk 中实现。

        【讨论】:

          【解决方案6】:

          下面是一种将它作为 Perl 单线的方法:

          perl -ne '$m = 1 if /^insert_name_here attr/; print if $m; $m = 0 if /^\)$/' file.txt
          

          【讨论】: