【问题标题】:How to filter characters if lines are aligned to right side using awk or sed如果使用 awk 或 sed 将行与右侧对齐,如何过滤字符
【发布时间】:2016-09-01 20:36:39
【问题描述】:

我有一个命令的输出,这里给出。

                        ID   SPEED    NCPU    PMEM    VMEM      EP   NPROC      IO    IOPS
                        p1     100       1   1024M   1024M      20     100    1024    1024
                        a2     100       1   1024M   1024M      20     100    1024    1024
                     b2 b3     100       1   1024M   1024M      20     100    1024    1024
                  c3 c4 c5     100       1   1024M   1024M      20     100       0    1024

我需要过滤掉“ID”列下的值

命令awk '{print $1} 只打印:

p1
a2
b2
c3 

这是不想要的输出。

我正在寻找的输出是。

p1
a2
b2 b3
c3 c4 c5

【问题讨论】:

    标签: awk sed pattern-matching


    【解决方案1】:

    查看它的一种方法是“从数据中删除最后八列”:

    awk '{ $(NF-8+1) = ""; NF -= 8; print }'
    

    输出:

    ID
    p1
    a2
    b2 b3
    c3 c4 c5
    

    如果您不分配给$(NF-8+1)awk 不会认为$0 可能已更改,因此它会打印未更改的行。并且使用$(NF-8+1) 将允许您使用变量来指定要省略多少尾随列:

    awk -v omit="${howmany:-8}" '{ $(NF-omit+1) = ""; NF -= omit; print }'
    

    如果您设置 shell 变量 howmany=6,您也会看到“SPEED”和“NCPU”列:

    ID SPEED NCPU
    p1 100 1
    a2 100 1
    b2 b3 100 1
    c3 c4 c5 100 1
    

    使用 awk 的 BSD 和 GNU 变体进行测试。

    【讨论】:

    • 这依赖于未定义的行为,所以 YMMV。 POSIX 定义了如果增加 NF 会发生什么(您会得到一堆额外的空字段),但不会定义当您减少它时会发生什么,这取决于实现。不过,您可以使用 sub(/( +[^ ]+){8}$/,"") 获得 POSIX 方法。
    • 这似乎是一个公平的评论——至少根据 POSIX awk 规范。您可以通过分配给超出当前值的字段来增加NF$(NF+1) = 6; $(NF+1) = 7; 实际上分配给两个不同的字段,这不是很明显。不清楚是定义了NF += 2,还是定义了NF -= 7。它恰好起作用;目前尚不清楚它是否必须工作。
    【解决方案2】:
    $ awk 'NR>1{$0=substr($0,1,26); $1=$1; print}' file
    p1
    a2
    b2 b3
    c3 c4 c5
    

    但请注意,处理固定宽度字段的一般解决方案是使用 GNU awk 的 FIELDWIDTHS 变量而不是 FS:

    $ awk -v FIELDWIDTHS="26 8 8 8" '{for (i=1;i<=NF;i++) printf "<%s>%s", gensub(/^ +/,"",1,$i), (i<NF ? OFS : ORS)}' file
    <ID> <SPEED> <NCPU> <PMEM>
    <p1> <100> <1> <1024M>
    <a2> <100> <1> <1024M>
    <b2 b3> <100> <1> <1024M>
    <c3 c4 c5> <100> <1> <1024M>
    

    我添加了 gensub() 来删除前导空格。见:

    【讨论】:

      【解决方案3】:

      我还会添加 sed 选项:

      $ sed -ne '2,$s/^[ ]\+//g; s/\(.*[[:alpha:]][[:digit:]]\).*/\1/p' file
      p1
      a2
      b2 b3
      c3 c4 c5
      

      地点:

      2,$ - start with 2nd line
      s/^[ ]\+//g - remove leading spaces
      s/\(.*[[:alpha:]][[:digit:]]\).*/\1/p - match until last [alpha][digit] and print only that part
      

      注意:我假设 ID 总是像 a1b2 等。

      【讨论】:

        【解决方案4】:

        如果字段的字符数是固定的

        grep -oE '^.{26}' file
        

        如果不需要第一行,则将输出通过管道传输到tail -n +2.. 或使用sed

        sed -nE '2,$ s/^(.{26}).*/\1/p' file
        

        如果字段数是固定的:

        $ sed -nE '2,$ s/(\s+\S+){8}$//p' file
                                p1
                                a2
                             b2 b3
                          c3 c4 c5
        

        【讨论】:

          猜你喜欢
          • 2011-04-20
          • 2015-12-03
          • 1970-01-01
          • 1970-01-01
          • 2012-01-04
          • 1970-01-01
          • 2017-04-27
          • 1970-01-01
          • 2020-02-25
          相关资源
          最近更新 更多