awk模式总是匹配最后一条记录?

时间:2016-07-09 23:02:53

标签: linux bash shell awk gawk

我正在从zsh切换到bash,我需要生成一个bash脚本,可以删除$PATH中的重复条目,而无需重新排序条目(因此没有sort -d魔法)。 zsh有一些很好的数组处理快捷方式,可以很容易地有效地执行此操作,但我不知道bash中有这样的快捷方式。我遇到了this answer,它已经让我90%的方式,但有一个小问题,我想更好地理解。看来,当我运行awk命令时,处理的最后一条记录与模式不匹配。

$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc"
aa:bb:cc:cc
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb"
aa:bb:cc:bb
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:" # note trailing colon
aa:bb:cc:

我不太了解awk,知道它为什么会这样,但我已经设法通过使用这样的中间数组来解决这个问题。

array=($(awk 'BEGIN{RS=":";ORS=" "}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:"))
# Use a subshell to avoid modifying $IFS in current context
echo $(export IFS=":"; echo "${array[*]}")
aa:bb:cc

然而,这似乎是次优解决方案,所以我的问题是:我在awk命令中做了哪些错误导致最终记录处理时出现误报匹配?

2 个答案:

答案 0 :(得分:4)

原始字符串中的最后一条记录是cc\n,与cc不同。如果不确定任何语言在任何程序中发生了什么,添加一些打印语句就是调试/调查的第1步:

$ awk 'BEGIN{RS=ORS=":"} {print "<"$0">"}' <<<"aa:bb:cc:aa:bb:cc"
<aa>:<bb>:<cc>:<aa>:<bb>:<cc
>:$

如果您希望RS为:\n,那么请说明(至少使用GNU awk):

$ awk 'BEGIN{RS="[:\n]"; ORS=":"} !a[$0]++' <<<"aa:bb:cc:aa:bb:cc"
aa:bb:cc:$

以上所有内容中的$是我的提示。

答案 1 :(得分:0)

另一种可能的解决方法,而不是bash阵列解决方案

$ echo "aa:bb:cc:aa:bb:cc" | tr ':' '\n' | awk '!a[$0]++' | paste -sd:
aa:bb:cc