如何在AWK中一次性删除多个列和字段分隔符?

6
我有一个包含几千列的大文件。我想用Bash中的AWK一次性删除一些特定的列和字段分隔符。
我可以使用这个单行命令(将删除第3列及其相应的字段分隔符)逐个删除一列:
awk -vkf=3 -vFS="\t" -vOFS="\t" '{for(i=kf; i<NF;i++){ $i=$(i+1);}; NF--; print}' < Big_File

然而,我想一次删除多列......有人能帮我解决吗?

不,不是这样的。在这里,你选择特定的列,而不是在一个区间内的列... - Bebe
我不太同意。在上述两个问题中,都提到了删除范围和列列表的答案。 - Thor
对于 AWK,我真的找不到它... - Bebe
1
我在投票时过于匆忙了。实际上,这两个问题都有使用“cut”进行操作的答案,但没有使用“awk”的答案。我投票要求重新开放。 - Thor
4个回答

5
您可以像这样将要从shell中删除的列的列表传递给awk:
awk -vkf="3,5,11" ...

然后在 awk 程序中将其解析成数组:

split(kf,kf_array,",")

然后遍历所有列,并测试每个特定的列是否在kf_array中,可能会跳过它。

另一种可能性是多次调用您的一行代码:-)


4

这里是Kamil的想法的实现:

awk -v remove="3,8,5" '
  BEGIN {
    OFS=FS="\t"
    split(remove,a,",")
    for (i in a) b[a[i]]=1
  }                                                          
  {
    j=1
    for (i=1;i<=NF;++i) {
      if (!(i in b)) { 
        $j=$i
        ++j
      }
    }
    NF=j-1
    print
  }
'

谢谢,不过那个脚本改变了字段分隔符,我想继续使用“制表符”作为分隔符,有什么建议吗? - Bebe
在-v和变量赋值之间不加空格会使您的解决方案过于依赖gawk。此外,如果您要将FS和OFS设置为相同的值,则在BEGIN部分中只使用FS=OFS="\t"更加简洁。 - Ed Morton

3
如果你可以使用 cut 而不是 awk,那么这个更容易使用 cut
例如:从文件中获取第1列、第3列和第50列及以后的内容: cut -f1,3,50- file

0

类似这样的代码应该可以运行:

awk -F'\t' -v remove='3|8|5' '
{
   rec=ofs=""
   for (i=1;i<=NF;i++) {
      if (i !~ "^(" remove ")$" ) {
         rec = rec ofs $i
         ofs = FS
      }
   }
   print rec
}
' file

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接