Skip to main content

Linux 核心命令

文件查看编辑命令 uniq

uniq 命令在 Linux 中是一个非常有用的工具,通常用于去除相邻的重复行。

不过,有一个很重要的前提:uniq 只能处理相邻的重复行。这意味着,如果重复的行不是紧挨着的,uniq 会把它们当成不同的行。

为了让 uniq 能正确地处理所有重复行,我们通常会先用 sort 命令对内容进行排序,确保所有相同的行都排列在一起。

1. 基本用法:去除相邻的重复行

最基本的用法就是直接使用 uniq 命令,它会读取文件内容,然后输出一份去除了相邻重复行的版本。

假设我们有一个文件 fruits.txt,内容如下:

apple
banana
apple
orange
banana
banana

直接对它使用 uniq

uniq fruits.txt

你会得到下面的输出:

apple
banana
apple
orange
banana

注意到第一个 apple 和第二个 apple 并没有被当成重复项,因为它们中间隔着一行 banana。这就是为什么我们通常需要先 sort

2. 先排序再处理:最常见的用法

这是 uniq 最经典的使用场景。我们通过管道符 |sort 命令的输出结果直接传给 uniq 命令。

我们还是用上面的 fruits.txt 文件。

sort fruits.txt | uniq

sort fruits.txt 会先输出:

apple
apple
banana
banana
banana
orange

然后 uniq 再处理这个排好序的结果,最终的输出就是:

apple
banana
orange

这样就实现了真正意义上的“全文去重”。

3. 统计每一行出现的次数

如果你不仅想去重,还想知道每一行到底出现了多少次,可以使用 -c (count) 选项。

sort fruits.txt | uniq -c

输出结果会在每一行的前面加上一个数字,表示它在排序后的文件中连续出现的次数。

      2 apple
      3 banana
      1 orange

这个命令对于快速统计日志中某个事件的发生频率非常有用。

4. 只显示重复过的行

有时候你可能只关心哪些行是重复出现的,不关心那些只出现一次的行。这时候可以用 -d (duplicated) 选项。

sort fruits.txt | uniq -d

这个命令会只输出那些至少出现过两次的行(去重后)。

apple
banana

5. 只显示唯一的行

-d 相反,-u (unique) 选项会只显示那些从头到尾只出现过一次的行。

sort fruits.txt | uniq -u

使用我们的例子,只有 orange 是独一无二的。

orange

6. 忽略大小写差异

默认情况下,uniq 是大小写敏感的('Apple' 和 'apple' 会被认为是不同的行)。如果你想在比较时忽略大小写,可以使用 -i (ignore-case) 选项。

假设我们有一个文件 names.txt

Alex
alex
Bob
Chris
Bob

如果我们直接 sort | uniq

sort names.txt | uniq

输出会是:

Alex
Bob
alex
Chris

Alexalex 被当成了不同的行。现在我们加上 -i 选项:

sort names.txt | uniq -i

输出就变成了:

Alex
Bob
Chris

注意:sort 命令本身也需要忽略大小写才能把 Alexalex 排在一起,所以更严谨的写法是 sort -f names.txt | uniq -i

7. 跳过开头的指定字段

在处理一些格式化的文本(比如日志文件)时,你可能想基于某一列或某几列来判断是否重复,而不是整行比较。uniq 提供了 -f (fields) 选项来跳过行首的若干个字段。字段默认是由空格或制表符分隔的。

假设我们有一个日志文件 log.txt,记录了用户的操作:

10:00  user1  login
10:02  user2  login
10:03  user1  logout
10:05  user1  login

我们想找出哪些用户执行了连续相同的操作,但要忽略时间戳。我们可以跳过第一个字段(时间戳)。

uniq -f 1 log.txt

输出:

10:00  user1  login
10:02  user2  login
10:03  user1  logout
10:05  user1  login

在这个例子里,uniq 会从 user1 开始比较 10:00 user1 login10:02 user2 login,因为它们不同,所以都保留。它也会从 user1 开始比较 10:03 user1 logout10:05 user1 login,也不同。

如果我们只想找出连续登录的用户,可以这样:

# 假设有这样的日志
10:00 user1 login
10:01 user1 login
10:02 user2 login

uniq -f 1 log_with_duplicates.txt

它会跳过时间字段,发现 user1 login 是重复的,于是只保留第一条。

8. 跳过开头的指定字符

除了可以跳过字段,你还可以用 -s (skip-chars) 选项来精确地跳过行首的指定数量的字符。

假设文件 data.txt 内容如下,每一行的前5个字符是编号,我们想忽略编号来去重。

abc01:apple
abc03:apple
abc02:banana

然后用 uniq 跳过前6个字符(abc01:)。

uniq -s 6 data.txt

它会把第一行和第二行看作是相同的(因为都剩下 apple),所以输出会是:

abc01:apple
abc02:banana

-f-s 一起使用时,会先跳过 -f 指定的字段,然后再在剩下的内容里跳过 -s 指定的字符。