我正在尝试使用 uniq 查找文件中的所有非唯一行。我所说的非唯一是指我在上一行中已经看到的任何行。我认为“-D”选项可以做到这一点:
-D print all duplicate lines
但它不只是打印重复的行,而是打印全部当有多条线路时。我只想打印一行的第二份和后续副本。
我怎样才能做到这一点?
答案1
您需要 GNU 版本的小写 -d 选项。
# printf "a\na\na\nb\nb\nc\n" | uniq -d
a
b
答案2
使用 GNU 或 ast-open 实现uniq
:
uniq -D -u < input
(-D
本身是非标准的),但请注意,这是它删除的最后一个重复项,而不是第一个(如果您还使用-i
,-w
或,这会有所不同-f
)
可移植的是,您始终可以使用awk
:
awk 'NR > 1 && $0 "" == previous ""; {previous = $0}' < input
(与 is 的连接强制""
进行字符串比较,即使操作数看起来像数字)
仅比较前 9 个字符(请注意,这-w
也是一个 GNU 扩展,并且(当前)适用于字节,而不是字符(尽管其文档是这么说的)):
awk '{current = substr($0, 1, 9)}
NR > 1 && current == previous
{previous = current}' < input
""
(在这种情况下不需要连接,因为substr()
返回一个字符串)。
在 UTF-8 语言环境中,在输出上
printf '%s\n' StéphaneChazelas StéphaneUNIX StéphaneUnix
它StéphaneUnix
按预期给出 while uniq -w9 -D -u
(使用 GNU uniq
)给出StéphaneChazelas
并且StéphaneUNIX
按Stéphane
原样给出 8 个字符,但 UTF-8 中的 9 个字节,而 ast-openuniq
仅给出 StéphaneUNIX (awk
跳过第一次出现,uniq
删除最后一次出现)。
使用awk
,您还可以报告所有重复行,即使它们不与以下内容相邻:
awk 'seen[$0]++' < input
(请注意,它将内存中的所有唯一行存储在哈希表中)。
或者只考虑前 9 个字符:
awk 'seen[substr($0, 1, 9)]++' < input
答案3
解决方案是使用-c
uniq ,然后删除你想要的内容
e444$ ( echo a ; echo a ; echo b ; echo d ; echo d ; echo e ) | uniq -c
2 a
1 b
2 d
1 e
a
和d
是重复的 和b
是e
双重的
e444$ ( echo a ; echo a ; echo b ; echo d ; echo d ; echo e ) | uniq -c \
| sed -E '/^ *1 .$/d;s/^ *[0-9]+ //'
表达式的解释sed
:
/^ *1 .$/d
将删除所有唯一行
s/^ *[0-9]+ //
将删除计数器