如何删除AWK中的输入字段?

如何删除AWK中的输入字段?

我正在使用awk(或gawk) 转换一些数据,并希望在再次打印输出之前删除其中一个输入字段。

我想要实现的是:

~ $ echo 'field1,field2,field3' | awk -F, '{transform($1); delete($2); print $0;}'
new_field1,field3

我不能只分配一个空字符串,$2因为这会导致new_field1,,field3(注意两个逗号)。

我可以明确地只打印我想要的字段,但这不是很优雅,因为我的字段远多于 3 个,而且末尾还有可选字段(此处未显示)。这就是为什么我更喜欢print $0.只需要先删除一些字段即可。

任何想法?

答案1

在 awk 中删除字段是出了名的困难。这似乎是一个简单的(而且经常是必需的)操作,但它比应有的更难。

有没有办法完全删除 awk 中的字段,以便不打印多余的分隔符? 来自 Stack Overflow 的一个好方法。

我已经复制了rmcol()@ghoti 的答案中的函数,以便我们在 U&L 上有一个副本:

function rmcol(col,     i) {
  for (i=col; i<NF; i++) {
    $i=$(i+1)
  }
  NF--
}

它从当前输入行中删除指定的列,并减少字段计数器 ( NF) 以进行匹配。

我不知道你的transform()函数是做什么的,所以我什至不会尝试重复它 - 但这里有一个在单行rmcol()中使用的示例:awk

$ echo 'field1,field2,field3' | awk -F, -v OFS=, '
  function rmcol(col,     i) {
    for (i=col; i<NF; i++) {
      $i=$(i+1)
    }
    NF--
  }

  { rmcol(2); print; }
  '
field1,field3

顺便说一句,如果您需要从输入行中删除多个字段,最好/最简单的方法是按相反的顺序删除它们。那是,首先删除编号最大的字段。为什么?因为每次删除较低编号的字段时,较高编号的字段都会重新编号,这使得很难跟踪哪个字段编号属于哪个字段。


顺便说一句,delete()inawk用于删除数组的元素 - 而不是用于从输入行删除字段。您可以将split()每个输入行( on FS)放入一个数组中并删除第二个数组元素,但随后您必须编写一个join()函数来打印数组,并用逗号(或OFS)分隔每个字段。

即使这样做也会比预期的更复杂,因为所有数组awk都是关联数组(即它们是不是数字索引) - 所以delete(array[2]) 惯于自动将数组元素 3+ 移动到元素 2+ 中。您必须编写自己的包装函数,才能对数组执行与输入字段delete()几乎相同的操作。rmcol()

答案2

一些替代方案

1)预处理输入以首先删除字段,cut如果字段分隔符是单个字符,则很容易做到

$ s='field1,field2,field3'
$ # use 'cut -d, -f1,3-' if --complement option is not available
$ echo "$s" | cut -d, --complement -f2
field1,field3
$ echo "$s" | cut -d, --complement -f2 | awk 'BEGIN{FS=OFS=","} {$1="new"} 1'
new,field3

2)使用perl

$ # indexing starts from 0, the array @F contains the input fields
$ # $#F will give index of last element in the array
$ echo "$s" | perl -F, -lane '$F[0]="new"; print join ",", @F[0,2..$#F]'
new,field3

答案3

用 重写 $0gensub可能会导致更简单的脚本。

要从给定的 input 中删除字段 2 和 3,您可以使用从 $0 中删除字段gensub并重新生成 $0 (以及所有字段),如下所示:

> echo 'field1,field2,field3' \
    | awk -F, '{OFS=","; \
                transform($1); \
                $0=gensub(/[^,]*,/,"",2); \
                print}'
new_field1,field3

请注意,这print相当于print $0.

相关内容