考虑我有一个测试文件(test.txt)包含的数据如下
1,2
2,3
2,1
2,2
3,1
1,3
2,5
4,1
我希望删除每对重复项,例如对于对 (1,2) 和 (2,1),应该打印其中任何一个(先到先打印)。预期输出为
1,2
2,3
3,1
2,2
2,5
4,1
我已经尝试过这个命令,awk -F"," '!seen[$1,$2]++ && !seen[$2,$1]' test.txt
.它打印为
1,2
2,3
3,1
2,5
4,1
为什么 2,2 对没有打印?还有如何获得预期的输出。
如前所述,问题来自逻辑评估中的短路。
为了规避这种情况,一种选择是在 2D 表seen
中测试和设置一个值:
awk -F"," '!seen[($1<$2?$1:$2)+0, ($1>$2?$1:$2)+0]++'
基本上,它使用两个值中的最小值和最大值作为索引,因此一个测试而不是两个测试,然后递增插槽。
请注意强制转换为整数的+0
指令。必须这样做,因为字段包含额外的空格,包括最终的行尾。
常见的、惯用的 2 字段解决方案,在任何 UNIX 盒子上的任何 shell 中具有任何 awk:
$ awk -F, '!seen[$1>$2 ? $1 FS $2 : $2 FS $1]++' file
1,2
2,3
2,2
3,1
2,5
4,1
对于使用 GNU awk 进行asort()
的任意数量的字段:
awk -F, '{split($0,a); asort(a); for (i=1;i<=NF;i++) k=(i>1 ? k FS : "") a[i]} !seen[k]++' file
例如,对于包含 1,2,3 和 2,3,4 的每个排列的输入文件:
$ cat file
1,2,3
1,3,2
2,1,3
2,3,1
3,1,2
3,2,1
2,3,4
2,4,3
3,2,4
3,4,2
4,2,3
4,3,2
$ awk -F, '{split($0,a); asort(a); for (i=1;i<=NF;i++) k=(i>1 ? k FS : "") a[i]} !seen[k]++' file
1,2,3
2,3,4
>我不擅长awk
,但使用其他工具很容易做到这一点。
如果顺序无关紧要,让我们复制每行,顺序颠倒。然后我们可以只用sort -u
来打印独特的行:
cat <<EOF |
1,2
2,3
2,1
2,2
3,1
1,3
2,5
4,1
EOF
sed 's/(.*),(.*)/1,2:1,2n2,1:1,2/' |
sort -u -t: -k1,1 |
cut -d: -f2 |
sort -u
sed
utlity 变换了这条线:
1,2
到:
1,2:1,2
2,1:1,2
然后我使用第一列删除重复项,仅用:
和sort -u -t: -k1,1
分隔。然后cut -d: -f2
删除第一列。然后我再次对唯一行进行排序,因为我们会有重复的行(例如,当1,2
对于1,2
和2,1
都是唯一的)。结果是:
1,2
2,2
2,3
2,5
3,1
4,1
如果顺序不重要,您可以轻松使用awk、sort和uniq组合。
awk -F "," '$1 < $2 { printf "%d,%dn", $1,$2} $2 <= $1 {printf "%d,%dn", $2, $1}' file | sort | uniq
此处的 awk 操作通过对数字进行排序来规范输出,以便2,1
变得1,2