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

Awk pattern always matches last record?

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

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

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

array=($(awk 'BEGIN{RS=":";ORS=" "}!a[[=11=]]++' <<<"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 命令中做错了什么导致处理的最终记录出现误报匹配?

原始字符串中的最后一条记录是 cc\n,与 cc 不同。当不确定任何语言的任何程序中发生了什么时,添加一些打印语句是 debugging/investigating:

的第 1 步
$ awk 'BEGIN{RS=ORS=":"} {print "<"[=10=]">"}' <<<"aa:bb:cc:aa:bb:cc"
<aa>:<bb>:<cc>:<aa>:<bb>:<cc
>:$

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

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

以上的$是我的提示

另一种可能的解决方法,而不是您的 bash 数组解决方案

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