使用您的示例生成用于测试的输入:
printf 'one\nfour\ntwo\nthree\nfour\n'
处理此问题的最简单方法是将数据反转两次。以下适用于 BSD 和 OS X:
command | tail -r | awk '!a[$0]++' | tail -r
但该-r
选项并不通用。如果您使用的是 Linux,您可以使用coreutils 中的tac
命令(与 的相反)生成相同的效果:cat
command | tac | awk '!a[$0]++' | tac
如果这些都不起作用(即您使用的是 HP/UX 或更旧的 Solaris 等),您可以使用以下方法来扭转事情sed
:
command | sed '1!G;h;$!d' | awk '!a[$0]++' | sed '1!G;h;$!d'
当然,你也可以用 perl 做到这一点:
command | perl -e 'print reverse <>' | awk '!a[$0]++' | perl -e 'print reverse <>'
但是,如果您的系统上可以使用 perl,您不妨简化管道并完全跳过 awk:
command | perl -e '$a{$_}++ or print for reverse <>'
不过,我从来没有真正喜欢过 perl,而且我确实喜欢在 shell 中做事。如果您使用 bash(版本 4 或更高版本),并且不太关心性能,则可以直接在 shell 中实现一个数组:
mapfile -t a < <(command)
declare -A b;
for (( i=${#a[@]}-1 ; i>=0; i-- )); do ((b[${a[$i]}]++)) || echo "${a[$i]}"; done
无需外部工具。:-)
更新:
受到sudo_O's answer 的启发(或可能受到挑战),这里还有一个在 BSD 上的纯 awk 中工作的选项(即不需要 GNU awk):
command | awk '{a[NR]=$0;b[$0]=NR} END {for(i=1;i<=NR;i++) if(i==b[a[i]]) print a[i]}'
请注意,这会将所有输入存储在内存中两次,因此它可能不适合大型数据集。