问题 有没有办法完全删除awk中的字段,以便不打印额外的分隔符?


请考虑以下命令:

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

当我设置$ 2 = $ 3 =“”时,获得与写入相同效果的预期效果:

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

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

是否可以实际删除$ 2和$ 3?

注意:如果这是在Linux上 bash,上面的正确陈述如下,但Windows不能很好地处理单引号 cmd.exe

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

12567
2018-05-21 22:42


起源

您应该对外部集使用单引号,然后您不必在脚本中转义双引号。如果你使用外部集的双引号,那么你可以嵌入shell变量,使用 -v 改为做变量传递。 - Dennis Williamson
我在Windows中使用awk。由于某种原因,Cmd.exe与单引号不匹配。 - merlin2011
我在10多年前做过这个,(我想)。尝试做一个 $2=$3="";$0=$0。祝你好运。 - shellter
@shelter,试过,没运气。可能awk的版本已经改变了。谢谢你的建议! - merlin2011
好的,现在只是想出方框; - >, $2=$3="XYZ"; sub("\tXYZ\t", "", $0); $0=$0; print。不确定你是否需要两者 \t 在子。此外,如果您有原始的awk书,请检查那里,我认为这是我学习$ 0 = $ 0的地方。也许我忘记了一步。祝你好运。 - shellter


答案:


这是一个老人,但好。

正如Jonathan指出的那样,你不能删除中间的字段,但可以用其他字段的内容替换它们的内容。并且您可以创建一个可重用的函数来为您处理删除。

$ 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

5
2017-07-11 15:58



递减NF是每个POSIX的未定义行为。它将删除某些awks中的最后一个字段,在其他awks中被忽略,并且可以执行任何其他操作并仍然符合POSIX标准。 - Ed Morton


您不能删除中间的字段,但可以通过递减删除最后的字段 NF

因此,您可以将所有后面的字段向下移动以覆盖 $2 和 $3 然后减少 NF 两个,删除最后两个字段:

$ 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

7
2018-06-26 23:33





如果您只想删除列,则可以使用 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

HTH


3
2018-05-21 23:06



最后一个示例打印一个尾随选项卡。 {for (...) {printf delim $i; delim = "\t"}; printf "\n"} - Dennis Williamson
我关心gsub,因为还有其他字段合法地为空,我想要多个分隔符。 - merlin2011
@DennisWilliamson感谢您的更正。 - Steve
@ merlin2011查看我的更改。 HTH。 - Steve


一种方法是删除像你一样的字段,并删除多余的空格 gsub

awk 'BEGIN { FS = "\t" } { $2 = $3 = ""; gsub( /\s+/, "\t" ); print }' input-file

1
2018-06-27 20:48





在自杀史蒂夫的回答中,我想建议一个更多的解决方案,但使用sed而不是awk。

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

sed -i 's/\(.*,\).*,.*,\(.*\)/\1\2/' FILENAME

1
2017-09-05 22:46





我可以想到在不使用循环的情况下在Awk中执行此操作的唯一方法是使用 gsub 上 $0 结合相邻 FS

$ echo {1..10} | awk '{$2=$3=""; gsub(FS"+",FS); print}'
1 4 5 6 7 8 9 10

0
2018-04-18 02:46





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

$ echo“1,2 ,,, 5”| tr -s','

1,2,5


0
2018-01-13 19:16





echo one two three four five six|awk '{
print $0
is3=$3
$3=""
print $0
print is3
}'

一二三四五六

一二四五六


-1
2017-12-31 04:12