考虑我有一个测试文件(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不打印?还有如何获得预期的输出。
答案 0 :(得分:2)
如前所述,问题来自逻辑评估中的短路。
要避免这种情况,一种选择是在2D表seen
中测试并设置一个单一值:
awk -F"," '!seen[($1<$2?$1:$2)+0, ($1>$2?$1:$2)+0]++'
基本上,它使用两个值中的最小值和最大值作为索引,因此是一个测试而不是两个测试,然后增加插槽。
请注意+0
指令,该指令强制转换为整数。之所以必须这样做,是因为字段包含了额外的空格,包括最终的行尾。
答案 1 :(得分:1)
在任何UNIX机器上的任何外壳中都有任何awk的通用,惯用的2字段解决方案:
$ awk -F, '!seen[$1>$2 ? $1 FS $2 : $2 FS $1]++' file
1,2
2,3
2,2
3,1
2,5
4,1
以及使用asort()
使用GNU awk的任意数量的字段:
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
答案 2 :(得分:0)
我在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,\2\n\2,\1:\1,\2/' |
sort -u -t: -k1,1 |
cut -d: -f2 |
sort -u
sed
实用工具转换了这一行:
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
答案 3 :(得分:0)
如果顺序不重要,则可以轻松使用 awk ,排序和 uniq 组合。
awk -F "," '$1 < $2 { printf "%d,%d\n", $1,$2} $2 <= $1 {printf "%d,%d\n", $2, $1}' file | sort | uniq
此处的awk操作通过对数字进行排序来标准化输出,因此2,1
将变为1,2