Unix命令行文本处理之:管道的艺术

发布于 2025-09-27 分类: Linux

命令行里的“管道工”

在我们这个时代,电脑和手机的图形与音频功能早已超出了70年代终端用户的想象。然而,文本(text)依然是组织和分类文件的核心方式。无论是文件名本身,手机照片中嵌入的GPS坐标,还是音频文件里的元数据,文本在计算的方方面面都扮演着至关重要的角色。幸运的是,Linux 命令行提供了一系列强大的工具来处理文本内容,更棒的是,它还允许我们将这些工具连接起来,创造出更强大的功能。

让我们从一个简单的问题开始:你的 combined.txt 文件里有多少行?wc (word count,字数统计) 命令可以告诉我们答案。使用 -l 参数,我们可以让它只统计行数(它同样可以统计字符数和单词数):

wc -l combined.txt

类似地,如果你想知道你的主目录(home directory)下有多少个文件和文件夹,可以这样做:

ls ~ > file_list.txt
wc -l file_list.txt
rm file_list.txt

这个方法可行,但为了统计数量而特意创建一个临时文件,用完后马上又删除它,似乎有点小题大做。幸运的是,Unix 命令行提供了一种“捷径”,可以避免创建临时文件。它能将一个命令的输出(称为标准输出STDOUT)直接作为另一个命令的输入(称为标准输入STDIN)。这个过程就像在两个命令之间连接了一根水管,因此,这个操作被称为管道(piping)。

下面演示如何用管道将 ls 命令的输出直接传送给 wc

ls ~ | wc -l

请注意,这个过程中没有创建任何临时文件,也不需要指定文件名。管道完全在内存中操作。大多数 Unix 命令行工具,在没有指定输入文件时,都会默认从管道读取数据。

观察上面的命令,它由两个独立的部分组成:ls ~(列出主目录内容)和 wc -l(统计行数),它们之间用一个竖线字符 | 分隔开。将命令串联起来的这种做法非常普遍,以至于 | 这个字符本身通常就被称作管道符

管道符两边的空格主要是为了美观和清晰,并不是必需的。下面这个例子同样有效,它会告诉我们 /etc 目录下的项目数量:

ls /etc|wc -l

哇!这个目录下的文件可真不少。如果我们想把它们全部列出来,肯定会超出整个屏幕的显示范围。之前我们学过,当命令输出内容太多时,最好使用 less 来分页查看。这个技巧在使用管道时同样适用(别忘了,按 q 键退出 less):

ls /etc | less

构建命令管道

回到我们自己的文件。我们已经知道如何统计 combined.txt 的总行数了,但考虑到这个文件是由几个相同文件多次拼接而成的,我们不禁好奇:其中有多少行是独一无二的呢?

Unix 有一个 uniq 命令,它可以筛选出不重复的行。所以,我们的思路是:先用 cat 命令读出文件内容,然后通过管道传给 uniq。但我们最终只想要一个计数,所以还需要再接上 wc。幸运的是,命令行并不限制你只能使用一个管道,我们可以根据需要串联任意多个命令:

cat combined.txt | uniq | wc -l

执行后,你可能会发现得到的结果和文件的总行数相差无几,甚至完全一样。这肯定不对劲吧?为了搞清楚状况,我们可以去掉最后一个管道,直接看看中间步骤的输出。如果文件很长,可以再把它“接”到 less 上方便查看:

cat combined.txt | uniq | less

检查输出后你会发现,大部分重复的行似乎都没有被移除。要理解原因,我们需要查阅一下 uniq 命令的文档。

善用“说明书”:man 命令

大多数命令行工具都附带了一份或长或短的“使用说明书”,我们可以通过 man (manual,手册) 命令来阅读它。man 命令的输出会自动通过分页器(通常是 less)显示,所以你可以自由地上下翻页,阅读完毕后按 q 键退出。

man uniq

因为这类文档是通过 man 命令访问的,所以通常被称为“man page”(手册页)。你会经常听到“查一下 man page 获取更多细节”这样的说法。手册页的格式通常很精炼,更像是一份快速参考,而非完整的教程。内容有时会非常技术化,但你通常可以跳过大部分内容,只关注你需要的那个选项或参数的说明。

uniq 的手册页就是一个典型例子。它以一行简短的命令描述开始,接着是使用方法的摘要,然后是每个选项的详细说明。在 DESCRIPTION(描述)部分的第一行,我们就找到了问题的答案:uniq 命令只会处理相邻的(adjacent)重复行。

解决难题:先排序,再筛选

那么,问题就变成了:如何重新排列文件的内容,让所有重复的行都挨在一起呢?答案很简单:对文件内容进行字母排序。

Unix 提供了一个 sort 命令来完成这项工作。快速查看一下 man sort,我们发现可以直接把文件名作为参数传给它。让我们看看它对我们的文件做了什么:

sort combined.txt | less

现在你应该能看到,文件的所有行都已按字母顺序重新排列,相同的行自然也就挨在了一起。这正是 uniq 命令需要的输入格式!现在,我们可以完成最终的任务了:统计文件中的唯一行数。

sort combined.txt | uniq | wc -l

这个命令链的逻辑是:

  1. sort combined.txt:读取文件并按行排序,将相同的行聚集在一起。
  2. uniq:接收排序后的数据,删除相邻的重复行。
  3. wc -l:接收 uniq 处理后的唯一行数据,并统计其数量。

正如你所见,通过管道将数据从一个命令流向另一个命令,构建起长长的命令链来处理数据,是一种极其强大的技术。它不仅减少了对临时文件的依赖,还为你节省了大量的键盘输入。一个长长的命令链初看起来可能令人生畏,但请记住,你随时可以将其拆解成一个个独立的命令(并查阅它们的手册页),从而更好地理解它的工作原理。


无处不在的手册

几乎所有的 Linux 命令行工具都带有手册页。不妨花点时间看看你已经学过的命令的手册:man lsman cpman rmdir 等等。甚至 man 命令本身也有手册页,当然,查看它的方式就是 man man


-- 感谢阅读 --