本文中描述的都是 GNU 版本的命令,因为 Linux 和 FreeBSD 都使用 GNU 实用工具。因此这些命令可以不加修改就应用到 Unix 系统中。
16.1 命令和选项变体
两个适用于 GNU 实用工具(Linux 和 FreeBSD 使用的实用工具)的特点。大多数 GNU 实
用工具都拥有两种类型的选项(选项变体):
- 短选项:包含一个 -(连字符),后面跟一个字符;
- 长选项:包含两个 --,后面给一个单词;
通常,大多数重要的选项都是短选项。大多数情况中,长选项或是段选项的同义词,或者是平常不需要的深奥选项。因此这里只讨论段选项。
但是对于 GNU 实用工具来说,大多数命令都识别 --help 长选项。使用这个选项可以显示几乎所有命令的语法,包括命令选项的摘要信息。例如:
cat--help16.2 过滤器
将几个程序按顺序组合起来,形成一个管道线,管道线几乎完全类似于组装线:
catnew old extra|grepHarley|sort|less这样通过管道连接起来的程序就是过滤器,例如上面的 cat、grep、sort 都是过滤器。更精确地讲,过滤器就是任何能够从标准输入读取文本数据并向标准输出写入文本数据(每次一行)的程序。
通常,大多数过滤器都被设计成工具,出色地完成一件事情。这里的“工具”就是指那些功能单一、设计精简、以文本流为接口、便于通过管道连接和组合的命令行程序。
更有趣的是,管道线中的第一个和最后一个程序不必是过滤器。例如 less 就不是过滤器。
16.3 是否应该创建自己的过滤器
创建自己的过滤器,所需要做的就是编写一个使用标准IO、每次一行地读取和写入文本数据的程序或者 shell 脚本。任何这样的程序都是过滤器,因此可以在管道线中使用。
但是在编写自己的程序之前,最好是先查找是否有现成的工具可用。尽量使用 Unix 中已有的工具组合在一起解决问题。
16.4 问题解决过程
目标是理解如何通过将许多过滤器组合成一个管道线来解决问题。如果需要,还可以使用不止一行命令行,甚至是包含一串命令的 shell脚本。但是,最聪明的 Unix人士大都使用一行
命令解决他们的问题,因此这就是您的目标。
如果有一个问题,并且希望使用过滤器和管道线来解决这个问题,那么解决步骤如下:
- 分解问题
将问题分解成多个部分,每个部分都可以由一个单独的程序执行。此时不用知道各部分任务需要使用什么工具来执行。 - 选择工具
大多数 Unix 问题都可以从一个拥有大约30个程序的相当小的工具箱中选择过滤器来加以解决。 - 与他人讨论
- 选择选项
检查选项,查找与工作相关的选项
当使用重定向、过滤器和管道线解决问题时,3个最重要的技能就是思考、RTFM以及询问他人的意见。
16.5 可能最简单的过滤器:cat
不做任何事的过滤器就是最简单的过滤器,即 cat,它所做的事情就是将标准输入的数据复制到标准输出,并且不以任何方式对数据做任何特殊处理或改变:
cat# 从键盘接收输入发送到显示器上,使用 ^D 发送 eof 信号创建小文件
cat 命令的第一种应用就是与重定向组合,快速地创建一个小文件:
cat>datacat>>data这种方式比启动文本编辑器键入文本要好很多。
显示一个短文件
只需要将标准输入重定向到希望显示的文件即可:
cat<data同时,也将显示一个长文件的末尾的部分。
不过使用 tail 命令,也可以快速地显示文件的末尾部分,而且大多数时候,tail 命令比 cat 命令出色。tail 命令只显示指定的行数,默认是10。
复制文件
cat 命令可以通过重定向标准输入和输出复制文件,例如,为了将文件 data 复制到另一个文件 newdata 中,可以输入:
cat<data>newdataUnix 中更好的命令来复制文件:cp 命令。
16.6 增强过滤器的功能
以下两个命令的功能相同:
cat<datacatdata这种方式,可以通过 cat 读取多个文件中的数据:
cat[file...]# file参数后的省略号意味着可以指定不止一个文件名通过这个命令,可以使用 cat 将任意多个文件的内容组合在一起:
catname address phone# 将三个文件的内容组合在一起显示在屏幕上catname address phone>info# 将三个文件的内容组合在一起保存到 info 文件中catname address phone|sort# 将三个文件的内容组合在一起发送给 sort 程序通过将 cat 扩展成可以从多个文件中读取数据,而不仅仅是从标准输入读取数据,我们已经失去了 Unix 总体设计的某些精美性。但大多数过滤器允许指定多个文件名作为参数,例如 sort 命令:
sortname address phonesortname address phone>infosortname address phone|grepHarley当一个过滤器,例如 cat 或 sort 这样的程序从标准输入读取数据时,它充当的是过滤器;但是它使用参数从文件中读取数据时,则不是充当一个过滤器来使用的。
16.7 最有用的过滤器列表
以下是最有用的 Unix 过滤器
| 过滤器 | 参阅(相关过滤器) | 作用 |
|---|---|---|
| awk | perl | 编程语言:操作文本 |
| cat | split、tac、rev | 组合文件:复制标准输入到标准输出 |
| clorm | cut、join、paste | 删除指定的数据列 |
| comm | cmp、diff、sdiff | 比较两个有序文件,显示区别 |
| cmp | comm、diff、sdiff | 比较两个文件 |
| cut | colrm、join、paste | 从数据中抽取指定列(字段) |
| diff | cmp、comm、sdiff | 比较两个文件,显示不同 |
| expand | unexpand | 将制表符转变为空格 |
| fold | fmt、pr | 将长行格式化成较短的行 |
| fmt | flold、pr | 格式化段落,从而使它们看上去更漂亮 |
| grep | look、strings | 选择包含指定模式的行 |
| head | tail | 从数据的开头选择行 |
| join | clorm、cut、paste | 基于公用字段,组合数据列 |
| look | grep | 选择以指定模式开头的行 |
| nl | wc | 创建行号 |
| paste | colrm、cut、join | 组合数据列 |
| perl | awk | 编程语言:操作文本、文件、进程 |
| pr | fold、fmt | 将文本格式化为页或者列 |
| rev | cat、tac | 每行数据中的字符串反序排列 |
| sdiff | cmp、comm、diff | 比较两个文件,显示区别 |
| sed | tr | 非交互式文本编辑 |
| sort | tsort、uniq | 排序数据:检查数据是否有序 |
| split | cat | 将大文件分隔成较小的文件 |
| strings | grep | 在二进制文件中搜索字符串 |
| tac | cat、rev | 组合文件,同时将文本行的顺序反转 |
| tail | head | 从数据的末尾选择行 |
| tr | sed | 改变或者删除选定的字符 |
| tsort | sort | 根据偏序创建全序 |
| unexpand | expand | 将空格转变成制表符 |
| uniq | sort | 选择重复/唯一行 |
| wc | nl | 统计行数、单词书和字符数 |
这些过滤器大多数都是30年前的,这些过滤器可以解决许多不同类型的问题,大多数情况下,使用的过滤器极少超过4个。awk 和 perl 是复杂的编程语言,可以用来编写在管道线中担当过滤器的程序。
16.8 组合文件:cat
cat 程序将数据不加改变地复制到标准输出。数据可以来源于标准输入或者一个或多个文件。
# cat 命令的语法:cat[-bns][file...]# cat 命令示例:cat>filecat>>filecat<filecatfilecat<file1>file2# 复制文件catfile1 file2 file3|lesscatfile1 file2 file3>file4catfile1 file2 file4|pregram关于 cat 命令,其最有用的选项为:
- -n(number,数字),此选项在每行前面加一个行号;
- -b(blank,空白),此选项和 -n 选项一起使用,告诉 cat 不要对空白行编号;
- -s(squeeze,挤压),此选项将多个连续空白行替换为一个空白行;
cat 命令的名称来源于一个古老的单词 “catenate”,它意味着 “to join in a chain”,catena 就是 chain 的拉丁语单词。
16.9 分割文件:split
cat 将两个或者更多个文件组合吃呢搞一个大的文件。而 split 程序将执行这一过程的逆过程:将一个大文件划分成几个较小的文件。其语法为:
split[-d][-a num][-l lines][file[prefix]]其中:
- num 是创建文件名时用作文件名后缀的字符或数字数量;
- lines 是每个新文件所包含行的最大数量;
- file 是输入文件的名称;
- prefix 是创建文件时使用的名称;
split 程序开发于20世纪70年代初,那个时候大的文本文件可能会产生问题。但现在这已经不再是个问题。
# 将 data 分隔为较小的文件,默认创建的小文件有 1000 行splitdata# 将 data 分隔为较小的文件,指定生成的小文件有 5000 行split-l5000data默认情况下,split 生成的小文件以字母 x 开头,后面跟两个字符的后缀,即 aa、ab、ac、ad 等。这种命名方式可以允许 26*26 共 676 个新文件名,即从 xaa 到 xzz。
如果使用了 -d(digits,数字) 选项,那么 split 就在文件名后面使用两个数字后缀(从 00 开始到 99,共100个文件),而不是两个字母后缀:
split-d -l5000data# 此命令生成的小文件名称为:x00、x01、x02、... 、x99如果不希望文件名以 x 开头,则可指定自己的名称用作生成的文件名的前缀:
split-d -l5000data harley# 此命令生成的小文件名称为:harley00、harley01、harley02、... 、harley99可以使用 -a 选项,后面给出希望在后缀中使用的数字或者字符的数量:
split-d -a3data# 此命令的生成的小文件名将使用 3 位数字后缀:x000、x001、x002、... 、x999split-a3data# 此命令的生成的小文件名将使用 3 位字母后缀:xaaa、xaab、xaac、... 、xzzz以上使用 -a 选项,可以使 split 命令分解很大的文件而不用担心用完文件名。
split 的案例:
split-d -l40supporters voter16.10 组合文件时翻转文本行的顺序:tac
tac 程序与 cat 程序相似,但它们之间有一个主要的区别,即 tac 在将文本写入到标准输出之前将文本行的顺序反转(名称 tac 就是 cat 的反向拼写),其语法为:
# 将输入的内容倒序并输出tac[file...]taclog>reverse-log# 将 log 中的内容倒序输出到 reverse-log 中假设,log 文件中的内容为:
Oct 01:event 1 took place Oct 02:event 2 took place Oct 03:event 3 took place Oct 04:event 4 took place在运行了上面的 tac 命令之后,reverse-log 文件中将包含:
Oct 04:event 4 took place Oct 03:event 3 took place Oct 02:event 2 took place Oct 01:event 1 took place需要使用 tac 的命令的场景很少,比如,为了查看一个日志文件的最新内容,最新的注释位于日志文件的末尾,那么就可以使用这个命令反向显示日志:
taclog|less16.11 反转字符的顺序:rev
tac 程序将文件中的各行的顺序反转,而 rev 可以反转各行中字符的顺序。rev 的名称就是来源于单词 reverse 反转、颠倒。其语法为:
rev[file...]# 其中 file 是文件名如果一个文件 data,该文件的内容为:
12345 abcde AxAxA那么在执行 rev data 之后,输出为:
54321 edcba AxAxA可以将每行中的顺序反转,并且将文件中行的顺序反转,只需要将 rev 的输出管道传送给 tac 即可:
revdata|tactacdata|rev上面这两个命令的最终输出是相同的!
16.12 从数据的开头或末尾选择数据行:head、tail
head 从数据的开头选择数据行;tail 从数据的末尾选择数据行。很多时候都需要使用 head 和 tail 显示文件的开头或末尾。当把 head 和 tail 作为过滤器使用时,其语法为:
head[-n lines]tail[-n lines]其中 lines 是希望选择的数据行的数量,默认情况下为 10。
假设,有一个程序 calculate,该程序生成许多数据,为了显示前10行数据,可以使用:
calculate|head# 显示前10行数据calculate|tail# 显示后10行数据calculate|head-n15# 显示前15行数据calculate|tail-n15# 显示后15行数据通常在复杂管道线的末尾使用 head 和 tail,以选取由前面命令生成的部分数据:
catdata1 data2 data3 data4|sort|head-n20# 显示所有文本排序后的前20行catdata1 data2 data3 data4|sort|tail-n20# 显示所有文本排序后的后20行catdata1 data2 data3 data4|sort|head-n300|lesscatdata1 data2 data3 data4|sort|tail>most-recent16.13 删除数据列:colrm
colrm(column remove,列移除)程序从标准输入读取数据,删除指定的数据列,然后将剩余数据写入标准输出。其语法为:
colrm[startcol[endcol]]其中 startcol 和 endcol 指定要移除区域的开头和末尾。列的编号从1开始。
如果只指定了起始列,那么 colrm 将移除从该列开始到这一行末尾的所有列。
如果既没有指定起始列也没有指定结束列,那么 colrm 不删除任何列。
例如,有一个文件 students,其文件内容如下:
012-34-5678 Ambercrombie, Al 95% A 123-45-6789 Barton, Barbara 65% C 234-56-7890 Canby, Carles 77% B 345-67-8901 Danfield, Deann 82% B当使用了如下命令之后:
colrm1430<students最终输出为:
012-34-5678 95% A 123-45-6789 65% C 234-56-7890 77% B 345-67-8901 82% Bwc -l 命令可以从标准输入读取数据,并统计行的数量。
dmesg 程序可以显示系统启动过程中生成的消息,一般来说,消息内容会很多。