有没有办法完全删除awk中的字段,这样就不会打印额外的分隔符?

有没有办法完全删除awk中的字段,这样就不会打印额外的分隔符?,awk,Awk,考虑以下命令: $gawk-F“\t”开始{OFS=\“\t\”}{$2=$3=\“\”\“打印$0}”Input.tsv 当我设置$2=$3=“”时,预期效果是获得与书写相同的效果: print $1,$4,$5...$NF 然而,实际发生的情况是,我得到了两个空字段,额外的字段分隔符仍在打印 是否可以实际删除$2和$3 注意:如果这是在Linux上的bash,上面的正确语句如下,但是Windows在cmd.exe中不能很好地处理单引号 $gawk-F'\t''开始{OFS=“\t”}{$

考虑以下命令:

$gawk-F“\t”开始{OFS=\“\t\”}{$2=$3=\“\”\“打印$0}”Input.tsv
当我设置
$2=$3=“”
时,预期效果是获得与书写相同的效果:

print $1,$4,$5...$NF
然而,实际发生的情况是,我得到了两个空字段,额外的字段分隔符仍在打印

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

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

$gawk-F'\t''开始{OFS=“\t”}{$2=$3=“;打印$0}”Input.tsv

如果您只是想删除列,可以使用
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
$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”{ for(i=1;i),不能删除中间的字段,但可以通过“<代码> NF< /COD> >递减字段的结尾来删除字段。

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

$ 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

$echo 1 2 3 4 5 6 7 | awk'{for(i=2;i一种方法是像您一样删除字段,并使用
gsub
删除额外的空格:

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

除了自杀Steve的答案之外,我还想提出一个解决方案,但使用
sed
代替
awk

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

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

在Awk中不使用循环的唯一方法是在
$0
上使用
gsub
组合相邻的
FS

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

这是一个老掉牙的好东西

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

$ 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
$cat test.awk
函数rmcol(col,i){
for(i=col;i)
一二三四五六

一二四五六


三个

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

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

中介绍的方法存在一些问题:

  • $i=$(i+1)
    的每个赋值都会强制awk重新生成记录
    $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
awk-v del=3'
开始{FS=FS;OFS=OFS}

{b=”“;for(i=1;最后一个示例打印一个尾随选项卡。
{for(…){printf delim$i;delim=“\t”};printf“\n”}
我担心gsub,因为还有其他字段是合法的空字段,我确实需要多个分隔符。@merlin2011查看我的更改。HTH。您应该对外部集使用单引号,那么您不必在脚本中转义双引号。如果您对外部集使用双引号,那么您可以嵌入shell变量,使用
-v
来进行变量传递。我在Windows中使用awk。出于某种原因,Cmd.exe不能很好地使用单引号。我想我10多年前就这样做了。尝试执行
$2=$3=“”$0=$0
。祝你好运。@SHEET,尝试过,没有运气。可能awk的版本已经更改了。不过谢谢你的建议!好的,现在只是想一想;->,
$2=$3=“XYZ”sub(“\tXYZ\t”,”,$0)$0=$0;print
。不确定您是否需要在sub中同时使用
\t
。此外,如果您有原始awk手册,请检查那里,我想这就是我学习$0=$0的地方。可能我忘记了一个步骤。祝您好运。递减NF是POSIX中未定义的行为。它将删除某些awk中的最后一个字段,在其他awk中被忽略,并且可以执行任何操作我知道这个问题,标准中没有规定,应该在可移植脚本中避免。我用gawk、mawk、nawk和busybox awk测试了这个问题,它们的行为都符合预期,你知道有任何awk不支持这种行为吗?@Thor MacOS/BSD awk就是其中之一。啊,我明白你的意思了,那是b因为在评估第一个操作时,
$0
已设置。您将看到使用
echo'abc'| awk'{NF--;$1=$1}的不同结果1'
。请注意,
NF
仍在递减,不同之处在于构建
$0
时。我发现,如果从文件(
-f
)而不是从命令行加载awk脚本,行为也会有所不同。哇,怪癖!一定会喜欢它们的。
echo'abc'| awk'{$1=$1;NF--}1'
产生相同的输出
ab
。未定义的行为确实-无法解释可能是更好的术语!:-)。