18

考虑以下命令:

$ gawk -F"\t" "BEGIN{OFS=\"\t\"}{$2=$3=\"\"; print $0}" Input.tsv

当我设置$2 = $3 = ""时,预期的效果是获得与写作相同的效果:

print $1,$4,$5...$NF

然而,实际发生的是我得到了两个空字段,额外的字段分隔符仍在打印。

是否可以实际删除$2and $3

注意:如果这是在 Linux 中bash,则上面的正确语句如下,但 Windows 不能很好地处理cmd.exe.

$ gawk -F'\t' 'BEGIN{OFS="\t"}{$2=$3=""; print $0}' Input.tsv
4

10 回答 10

8

这是一个老歌,但很好。

正如乔纳森所指出的,你不能删除中间的字段,但你可以用其他字段的内容替换它们的内容。您可以制作一个可重用的函数来为您处理删除。

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

{
  rmcol(3)
}

1

$ printf 'one two three four\ntest red green blue\n' | awk -f test.awk
one two four
test red blue
于 2016-07-11T15:58:57.030 回答
7

你不能删除中间的字段,但你可以删除最后的字段,方法是递减NF.

因此,您可以将所有后面的字段向下移动以覆盖$2然后$3递减NF2,这会擦除最后两个字段:

$ echo 1 2 3 4 5 6 7 | awk '{for(i=2; i<NF-1; ++i) $i=$(i+2); NF-=2; print $0}'
1 4 5 6 7
于 2012-06-26T23:33:50.913 回答
5

如果您只是想删除列,您可以使用cut

$ cut -f 1,4- file.txt

模仿cut

$ awk -F "\t" '{ for (i=1; i<=NF; i++) if (i != 2 && i != 3) { if (i == NF) printf $i"\n"; else printf $i"\t" } }' file.txt

相似地:

$ awk -F "\t" '{ delim =""; for (i=1; i<=NF; i++) if (i != 2 && i != 3) { printf delim $i; delim = "\t"; } printf "\n" }' file.txt

高温高压

于 2012-05-21T23:06:55.370 回答
1

一种方法可能是像您一样删除字段并使用以下命令删除多余的空格gsub

$ awk 'BEGIN { FS = "\t" } { $2 = $3 = ""; gsub( /\s+/, "\t" ); print }' input-file
于 2012-06-27T20:48:27.740 回答
1

除了 Suicidal Steve 的答案之外,我还想提出一个更多的解决方案,但sed使用awk.

它似乎比史蒂夫建议的用法更复杂cut。但这是更好的解决方案,因为sed -i允许就地编辑。

$ sed -i 's/\(.*,\).*,.*,\(.*\)/\1\2/' FILENAME
于 2013-09-05T22:46:25.170 回答
1

我能想到在 Awk 中不使用循环的唯一方法是使用gsubon$0来组合相邻FS

$ echo {1..10} | awk '{$2=$3=""; gsub(FS"+",FS); print}'
1 4 5 6 7 8 9 10
于 2014-04-18T02:46:14.453 回答
1

要从给定的输入文件中删除字段 2 和 3(假设使用制表符字段分隔符),您可以使用以下方法从 $0 中删除字段gensub并重新生成它:

awk -F '\t' 'BEGIN{OFS="\t"}\
             {$0=gensub(/[^\t]*\t/,"",3);\
              $0=gensub(/[^\t]*\t/,"",2);\
              print}' Input.tsv
于 2021-08-26T17:19:52.237 回答
0

好吧,如果目标是删除额外的分隔符,那么您可以tr在 Linux 上使用。例子:

$ echo "1,2,,,5" | tr -s ','
1,2,5
于 2017-01-13T19:16:02.610 回答
0

ghoti的答案中提出的方法存在一些问题:

  • awk 的每一次分配$i = $(i+1)力量都重建了记录$0。这意味着如果您有 100 个字段并且您想要删除字段 10,您将重建记录 90 次。

  • 手动更改的值NF不符合posix,并导致未定义的行为(如评论中所述)。

删除一组列的一种更麻烦但稳定可靠的方法是:

单列:

awk -v del=3 '
    BEGIN{FS=fs;OFS=ofs}
    { b=""; for(i=1;i<=NF;++i) if(i!=del) b=(b?b OFS:"") $i; $0=b }
    # do whatever you want to do
   ' file

多列:

awk -v del=3,5,7 '
    BEGIN{FS=fs;OFS=ofs; del="," del ","}
    { b=""; for(i=1;i<=NF;++i) if (del !~ ","i",") b=(b?b OFS:"") $i; $0=b }
    # do whatever you want to do
   ' file
于 2020-02-27T14:53:16.377 回答
-1
echo one two three four five six|awk '{
print $0
is3=$3
$3=""
print $0
print is3
}'

一二三四五六

一二四五六

于 2016-12-31T04:12:31.260 回答