【问题标题】:how to print entire block if it contains particular line with awk command?如果它包含带有 awk 命令的特定行,如何打印整个块?
【发布时间】:2020-06-24 19:46:56
【问题描述】:

我正在尝试使用 awk 命令处理来自 lshw -c network 的网络信息

输出如下所示:-

*-network:3
   description: Ethernet interface
   product: I350 Gigabit Network Connection
   vendor: Intel Corporation
   physical id: 0.3
   bus info: pci@0000:03:00.3
   logical name: eth1
   version: 01
   serial: xx:xx:xx:xx:xx:xx
   size: 1GB/s
   capacity: 1GB/s
   width: 32 bits
   clock: 33MHz
*-network                 
   description: Ethernet interface
   physical id: 1
   logical name: eth0
   serial: yy:yy:yy:yy:yy:yy
   capabilities: ethernet physical
   configuration: broadcast=yes driver=vif link=yes multicast=yes

我想以表格格式打印它,但前提是该块包含bus info:,这里只有第一个是合格的块,将被打印格式

最终输出:-

description   product   vendor   physical id   bus info ...
Ethernet..    I350 G..  Intel..  0.3           pci@0000:03:00.3

我最大的努力是:-

    lshw -c network | 
    awk -v FS=: 
    $0 ~ /*-network.*/ {
        v1 = NR; 
        v2 = ""; 
        v3 = 0
    } 

    NR > v1 && v3 == 0 {
        v2 = v2"@"$3
        } 

    $1 ~ /bus info.*/ {
        v3 = 1
        }  

    v3 == 1 {
        split(v2, ar, "@"); 
        for (t in ar) { print t}; 
        print $1
    }

没有运气

【问题讨论】:

    标签: awk text-processing


    【解决方案1】:

    每当您输入带有 tag(name) = value 映射的日期时,最好先创建一个数组来包含这些映射(下面的tag2val[]),然后您可以分析存在和/或具有特定值的字段的任何组合您喜欢并以您喜欢的任何顺序打印您喜欢的任何字段。例如:

    $ cat tst.awk
    BEGIN { OFS="\t" }
    /^[*]/ { prt() }
    {
        gsub(/^[[:space:]]+|[[:space:]]+$/,"")
        gsub(OFS," ")
        tag = val = $0
        sub(/[[:space:]]*:.*/,"",tag)
        sub(/[^:]+:[[:space:]]*/,"",val)
        tag2val[tag] = val
    }
    END { prt() }
    
    function prt(   flds, numFlds, fldNr) {
        numFlds = split("description,product,vendor,physical id,bus info",flds,/,/)
        if ( "bus info" in tag2val ) {
            if ( !doneHdr++ ) {
                for (fldNr=1; fldNr<=numFlds; fldNr++) {
                    tag = flds[fldNr]
                    printf "%s%s", tag, (fldNr<numFlds ? OFS : ORS)
                }
            }
            for (fldNr=1; fldNr<=numFlds; fldNr++) {
                tag = flds[fldNr]
                val = tag2val[tag]
                printf "%s%s", val, (fldNr<numFlds ? OFS : ORS)
            }
        }
        delete tag2val
    }
    

    .

    $ awk -f tst.awk file | column -s$'\t' -t
    description         product                          vendor             physical id  bus info
    Ethernet interface  I350 Gigabit Network Connection  Intel Corporation  0.3          pci@0000:03:00.3
    

    【讨论】:

      【解决方案2】:

      如果有人感兴趣:

      此命令有效:-

      lshw -c network | 
      awk -v out='description\tproduct\tvendor\tphysical id\tbus info\tlogical name\tversion\tserial\twidth\tclock\tcapabilities\tconfiguration\tresources' 
          -v v1=0 -F ': ' 
      ' $0 ~ /*-network.*/ {
          if (v1 == 1) {print out;} 
          out = ""; 
          v1=0 
      } 
      $1 ~ /bus info.*/ { 
          v1 = 1
          } 
      { 
          out = out"\t"$2 
      } 
      END{ 
          if (v1 == 1) print out 
      }'
      

      【讨论】:

      • 如果输入中包含bus info,则不会打印输入中的最后一条记录,并且仅在包含: 时打印部分数据(想象像@这样的产品名称987654325@),它将打印所有块,包括包含bus info的块,而不仅仅是包含它的块。
      • 我想现在它会打印出来。
      • 重新阅读我评论的最后一部分,想想你在哪里设置v1=0
      • 我更新检查了,这个命令,如果有问题请举个例子
      • 唯一剩下的问题是它只会打印部分数据,如果/当它包含:(想象一个像Ethernet: version 2这样的产品名称)。查看 I used tag = val = $0; sub(/[[:space:]]*:.*/,"",tag); sub(/[^:]+:[[:space:]]*/,"",val) 如何通过在第一个 : 处而不是在每个 : 处拆分行来使其健壮,而不是使用字段。
      猜你喜欢
      • 2021-03-23
      • 2016-12-14
      • 1970-01-01
      • 2014-04-04
      • 2023-01-12
      • 1970-01-01
      • 2016-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多