有没有一种方法来“列”uniq?
我有一个.csv文件,像这样:
stack2@example.com,2009-11-27 01:05:47.893000000,example.net,127.0.0.1 overflow@example.com,2009-11-27 00:58:29.793000000,example.net,255.255.255.0 overflow@example.com,2009-11-27 00:58:29.646465785,example.net,256.255.255.0 ...
我必须从文件中删除重复的电子邮件(整个行)(即上面例子中包含overflow@example.com
的行之一)。 如何仅在字段1上使用uniq
(以逗号分隔)? 据说, uniq
没有列的选项。
我尝试了一些东西sort | uniq
sort | uniq
但它不工作。
sort -u -t, -k1,1 file
-
-u
为唯一 -
-t,
所以逗号是分隔符 -
-k1,1
为关键字段1
testing结果:
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0 stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
awk -F"," '!_[$1]++' file
-
-F
设置字段分隔符。 -
$1
是第一个字段。 -
_[val]
在hash_
(一个常规variables)中查找val
。 -
++
增量,并返回旧值。 -
!
返回逻辑不是。 - 最后有一个隐含的印刷品。
考虑多个栏目。
根据第1列和第3列进行sorting并给出唯一列表:
sort -u -t : -k 1,1 -k 3,3 test.txt
-
-t :
冒号是分隔符 -
-k 1,1 -k 3,3
基于列1和列3
或者如果你想使用uniq:
<mycvs.cvs tr -s ',' ' ' | awk '{print $3" "$2" "$1}' | uniq -c -f2
得到:
1 01:05:47.893000000 2009-11-27 tack2@domain.com 2 00:58:29.793000000 2009-11-27 overflow@domain2.com 1
如果你想保留你可以使用的最后一个副本
tac a.csv | sort -u -t, -r -k1,1 |tac
这是我的要求
这里
tac
将逐行反转文件
这是一个非常漂亮的方式。
首先格式化内容,以便比较唯一性的列是固定宽度。 这样做的一种方法是使用awk printf与字段/列宽度说明符(“%15s”)。
现在,uniq的-f和-w选项可用于跳过前面的字段/列,并指定比较宽度(列宽)。
这里有三个例子。
在第一个例子中
1)暂时使感兴趣的列的宽度大于或等于字段的最大宽度。
2)使用-f uniq选项跳过前面的列,并使用-w uniq选项将宽度限制为tmp_fixed_width。
3)删除列的尾部空格,以“恢复”它的宽度(假设事先没有尾部空格)。
printf "%s" "$str" \ | awk '{ tmp_fixed_width=15; uniq_col=8; w=tmp_fixed_width-length($uniq_col); for (i=0;i<w;i++) { $uniq_col=$uniq_col" "}; printf "%s\n", $0 }' \ | uniq -f 7 -w 15 \ | awk '{ uniq_col=8; gsub(/ */, "", $uniq_col); printf "%s\n", $0 }'
在第二个例子中
创build一个新的uniq列1.然后在应用uniqfilter后将其删除。
printf "%s" "$str" \ | awk '{ uniq_col_1=4; printf "%15s %s\n", uniq_col_1, $0 }' \ | uniq -f 0 -w 15 \ | awk '{ $1=""; gsub(/^ */, "", $0); printf "%s\n", $0 }'
第三个例子与第二个例子相同,但对于多列。
printf "%s" "$str" \ | awk '{ uniq_col_1=4; uniq_col_2=8; printf "%5s %15s %s\n", uniq_col_1, uniq_col_2, $0 }' \ | uniq -f 0 -w 5 \ | uniq -f 1 -w 15 \ | awk '{ $1=$2=""; gsub(/^ */, "", $0); printf "%s\n", $0 }'
好了,比用awk隔离列更简单,如果你需要删除给定文件的某个值,那为什么不直接执行grep -v:
例如删除第二行中的值“col2”:col1,col2,col3,col4
grep -v ',col2,' file > file_minus_offending_lines
如果这还不够好,因为某些行可能会被不正确地剥离,可能会将匹配的值显示在不同的列中,您可以这样做:
awk隔离有问题的列:例如
awk -F, '{print $2 "|" $line}'
-F将分隔的字段设置为“,”,$ 2表示第2列,后面是一些自定义分隔符,然后是整行。 然后可以通过删除以冒犯值开头的行来进行过滤:
awk -F, '{print $2 "|" $line}' | grep -v ^BAD_VALUE
然后去除分隔符之前的东西:
awk -F, '{print $2 "|" $line}' | grep -v ^BAD_VALUE | sed 's/.*|//g'
(注意:sed命令是不严格的,因为它不包含转义值,sed模式也应该是“[^ |] +”(即任何不是分隔符)的东西,但是希望这个清楚。
通过首先sorting文件,然后可以应用uniq
。
它似乎sorting文件就好了:
$ cat test.csv overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0 stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 $ sort test.csv overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0 stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 $ sort test.csv | uniq overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0 stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
你也可以做一些AWK的魔法:
$ awk -F, '{ lines[$1] = $0 } END { for (l in lines) print lines[l] }' test.csv stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0