如何使用awk打印最后两列

124

我只想要最后两列被打印出来。


6
不太确定为什么这篇文章有87个赞,至少需要用一个例子来改进它。 - Arj
1
可能是因为这个问题本质上非常简单,没有例子也很容易理解,这种情况很少见,但在这种情况下似乎起作用了。我认为问题不在于缺乏信息,而更多地表现出缺乏独立研究的能力。 - DryLabRebel
这个问题也是这个问题的重复。 - DryLabRebel
1
这个回答解决了你的问题吗?在awk中打印倒数第二列/字段 - DryLabRebel
6个回答

229
您可以利用变量NF,该变量设置为输入记录中字段的总数:
awk '{print $(NF-1),"\t",$NF}' file

前提是您至少有2个字段。


1
由于我们今天很挑剔,所以您需要一个逗号:空格用于连接字段,逗号用于分隔打印语句中的字段。这将合并两个字段。 - jim mcnamara
20
现在你正在打印"field-OFS-tab-OFS-field"。应该是awk '{print $(NF-1) "\t" $NF}' file 或者 awk '{print $(NF-1), $NF}' file 或者 awk 'BEGIN{OFS="\t"} {print $(NF-1), $NF}' file - Dennis Williamson
1
仅仅是为了补充之前的评论,使用 '{print $x,"\t",$y}' 的问题在于 awk 会将每个逗号分隔的变量解释为它自己的字段,所以结果实际上会是 field1<space><tab><space>field2(因为默认情况下它会使用空格作为分隔符),而不是你期望的 field1<tab>field2。使用输出字段分隔符(OFS)几乎总是你想要的。 - DryLabRebel

18
awk '{print $NF-1, $NF}'  inputfile

注意:只有存在至少两列时,该方法才有效。对于只有一列的记录,你将会得到一个虚假的"-1 column1"


3
试一试,它确实适用于Solaris 9的awk和nawk。另一个选择是$(NF-1)。 - jim mcnamara
1
@coaddict - 我猜你没有使用不同的awk实现。旧版awk的行为已经被(可能是错误地)继承下来。我没有gawk进行测试,这可能是你所引用的。所以我不确定你的评论是怎么出现的。Linux默认的awk通常是gawk。我会进行测试并回复。同时,请尝试Soalris或HPUX或DGX或其他操作系统,以了解我所说的旧版awk。 - jim mcnamara
6
你可能被误导以为它奏效是因为你尝试了echo 1 2 3 | awk ...。在每个awk实现中,$NF-1都等价于($NF) - 1 - Stephane Chazelas
你提到一列输入时,第一个输出标记为-1,这表明@StephaneChazelas是正确的。如果你所说的关于“旧”awk行为的主张是正确的,那么第一个标记应该有效地是$0,即整个输入行。由于在这种情况下整个输入行只有一个标记 - 第一列也是唯一的列 - 你应该会得到那个一列值两次 - mklement0
1
@THESorcerer,尝试使用echo '5 4 3 2 1' | awk '{print $NF-1,$NF; print $(NF-1), $NF}'进行测试 - 或者任何其他输入,其中倒数第二个字段不是比最后一个字段小1。 - glenn jackman
显示剩余3条评论

7

@jim mcnamara:尝试使用括号将NF括起来,即$(NF-1)$(NF)代替$NF-1$NF(适用于Mac OS X 10.6.8上的FreeBSD awkgawk)。

echo '
1 2
2 3
one
one two three
' | gawk '{if (NF >= 2) print $(NF-1), $(NF);}'

# output:
# 1 2
# 2 3
# two three

我们之前已经考虑过()。我以为我们在讨论原始的旧awk行为的来源。 - jim mcnamara
+1 对于显示 $(NF-1) 的答案——至少比 $NF-1 更具可移植性,而且绝对不会产生歧义。虽然 $(NF) 也可以使用,但是这样有些多余。值得注意的是,防止少于2列的行也很重要,因为一列的行会使第一列的值重复出现两次,并且零列(即空行)会导致awk命令完全失败,因为试图访问索引-1的字段。 - mklement0
我们可以让它更简短一些:gawk 'NF>=2 {print $(NF-1), $NF}' - SergioAraujo

1

使用 gawk 出现了问题:

 gawk '{ print $NF-1, $NF}' filename
1 2
2 3
-1 one
-1 three
# cat filename
1 2
2 3
one
one two three

我刚将gawk安装在Solaris 10 M4000上:所以,在$NF-1与$(NF-1)问题上,gawk是罪魁祸首。下一个问题是POSIX说什么?
http://www.opengroup.org/onlinepubs/009695399/utilities/awk.html

这里没有明确的方向。不太好。gawk 暗示减法,其他 awk 暗示字段编号或减法。嗯。


1
你的样本输入文件的前两行并没有帮助,因为它们会产生相同的输出结果,无论使用哪种行为。请问您能否再次确认Solaris awk在这种情况下确实不像gawk那样的行为? - mklement0
关于您提供的 awk 规范链接:使用 $(NF-1) 的轶事论据是规范中计算字段索引的两个示例都使用了该形式:$(NF-1)$(NF+2)。然后有一个“awk表达式”部分,其中将 $expr 列为比 expr - expr 具有更高的[多]优先级。由于 NF 本身就是一个表达式,因此 $NF-1 应该被计算为 ($NF)-1。即使在所有情况下,确实存在将 $NF-1 计算为 $(NF-1) 的 awk 实现,这里学到的教训是使用 $(NF-1) 是安全和可移植的选择。 - mklement0

1

试试这个

$ cat /tmp/topfs.txt
/dev/sda2      xfs        32G   10G   22G  32% /

awk print last column
$ cat /tmp/topfs.txt | awk '{print $NF}'

awk print before last column
$ cat /tmp/topfs.txt | awk '{print $(NF-1)}'
32%

awk - print last two columns
$ cat /tmp/topfs.txt | awk '{print $(NF-1), $NF}'
32% /

1
请尝试以下操作,以考虑所有可能的情况:
awk '{print $(NF-1)"\t"$NF}'  file

或者

awk 'BEGIN{OFS="\t"}' file

或者

awk '{print $(NF-1), $NF} {print $(NF-1), $NF}' file

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