绝大多数命令行工作是针对文件的。我们会在本节中讨论如何观察及过滤文件内容,如何仅用一条命令就能从文件中提取所需信息,以及如何对文件的内容排序。
这些命令的语法基本上相同的:命令名 [选项] [文件],而且您可以在管道中使用这些命令。这些命令的功能都是根据特定的条件选择文件内容进行打印。
cat 工具会将指定的所有文件的全部内容依次打印到标准输出(一般是计算机的显示屏)。这是最常用的命令之一。例如,您可以使用:
# cat /var/log/mail/info
将邮件守护程序的日志文件打印到标准输出[23]。cat 命令的 -n
选项很有用,它能够同时打印行号。
某些文件,如守护程序日志文件(如果相应的守护程序运行了的话)可能非常大[24],在屏幕上打印全部内容可能没什么必要。您一般只是需要看看一个文件的某几行。您可以使用 tail 命令完成这一功能。默认情况下,下面的命令将会打印 /var/log/mail/info
文件的最后十行:
# tail /var/log/mail/info
像日志这样的文件应该是在不断变化的,因为与其相关的守护程序每时每刻都在记录着它所执行的动作和发生的事件。所以,如果您想要交互地观看日志文件的最新更动,请使用 -f
选项:
# tail -f /var/log/mail/info
在本例中,/var/log/mail/info
文件的所有更改都会立即打印到屏幕上。当您想要知道您系统的工作原理时,使用带 -f
选项的 tail 命令将非常有用。例如,通过查看 /var/log/messages
日志文件,您可以时刻跟踪系统信息和各种守护程序。
如果您指定 tail 同时处理多个文件,则它会先打印出一行文件名然后才是其内容。这一特性同样适用于 -f
选项,可以使您了解到系统各部分之间是如何协调运作的。
您可以使用 -n
选项显示文件的最后 n 行。例如,要显示最后 2 行,您应该执行:
# tail -n2 /var/log/mail/info
与其他命令一样,您可以同时使用多个选项。例如,同时使用 -n2
和 -f
将让您从该文件最后两行起不断看到写入该日至文件的新的文本行。
而 head 命令与 tail 十分相似,只是打印文件的头几行。默认情况下,下面的命令将会打印 /var/log/mail/info
文件的头十行:
# head /var/log/mail/info
和 tail 一样,您也可以使用 -n
选项指定要打印的行数。例如,要打印前两行,您应该执行:
# head -n2 /var/log/mail/info
您还可以组合使用这几条命令。例如,如果您想要只显示第九行和第十行,您可以先使用 head 命令选择文件的前十行,然后再将结果通过管道送到 tail 命令。
# head /var/log/mail/info | tail -n2
竖线后面的部分将选择最后两行,然后将其打印到屏幕。同样地,您也可以选择只打印文件的倒数第 20 行:
# tail -n20 /var/log/mail/info |head -n1
在本例中,我们让 tail 选择了文件的最后 20 行,然后将结果通过管道传送给 head。然后 head 命令将会从得到的数据中取出第一行打印到屏幕上。
假定您想要将上例中的结果在屏幕上显示的同时还保存到文件 results.txt
中。tee 工具可以帮到我们。其语法是:
tee [选项] [文件]
# tail -n20 /var/log/mail/info |head -n1|tee results.txt
我们再来举一个例子。我们想要选择最后 20 行,将其保存到 results.txt
,但是只在屏幕上显示这 20 行中的第一行。那么,我们应该输入:
# tail -n20 /var/log/mail/info |tee results.txt |head -n1
也许您会认为,不管是命令的名字,还是其缩写(“General Regular Expression Parser”,常规正则表达式分析器)都非常晦涩,但其功能和用法却十分简单:grep 将在一个或多个文件中搜索由参数给定的模式。其语法为
grep [选项] <模式> [一个或多个文件]
如果列出了多个文件,则会在结果的每一行开头附加相应的文件名。使用 -h
选项可以不显示这些文件名;使用 -l
选项可以只列出文件名。模式是一个正则表达式,尽管在大多数情况下只是一个简单的单词。下面列出了最常用的几个选项:
让我们回到对邮件守护程序日志文件的分析中。我们想要在 /var/log/mail/info
中找到包含 postfix
模式的所有行。我们就需要输入这个命令:
# grep postfix /var/log/mail/info
如果我们想要找到不与 postfix
模式匹配的所有行,我们就应该使用 -v
选项:
# grep -v postfix /var/log/mail/info
现在,假定我们想要查找关于成功发出邮件的全部信息。这样,我们需要找到邮件守护程序(包含 postfix
模式)在日志文件中添加的行,而且这些行还必须包含成功发送的信息(status=sent
)[25]:
# grep postfix /var/log/mail/info |grep status=sent
我们在本例中使用了两次 grep。这种方法虽然可以达到我们的目的,但显得有点繁琐。我们可以使用 fgrep 工具达到相同的效果。实际上,fgrep 只是一个调用 grep -F 的快捷方式。首先,我们需要创建一个包含需要匹配的模式的文件(每行一个)。该文件可以这样创建(我们用 patterns.txt
作为该文件的文件名):
# echo -e 'status=sent\npostfix' >./patterns.txt
可以用 cat 命令查看结果。\n
是一个特殊的模式,它表示“换行”。
然后,我们将会用 patterns.txt
文件中的模式列表作为参数调用 fgrep 工具,而不是“两次调用”grep:
# fgrep -f ./patterns.txt /var/log/mail/info
文件 ./patterns.txt
可以包含任意多个模式。例如,要选择已经成功发送给 li_si@mandriva.com
的邮件的有关信息,只需将此电子邮件地址添加到 ./patterns.txt
文件,试试这条命令:
# echo 'li_si@mandriva.com' >>./patterns.txt
显然,您可以将 grep 与 tail 或者 head 组合起来使用。如果我们想要查找发送给 li_si@mandriva.com
的最后第二封邮件,只需输入:
# fgrep -f ./patterns.txt /var/log/mail/info | tail -n2 | head -n1
使用 grep 只能查找固定模式的数据。那么怎样才能找出发送给 “ABC 公司” 每个员工的电子邮件呢?列出他们所有的电子邮件可不是一项简单的任务,可能最终会漏掉某人,或是需要手工查询。
与 fgrep 相类似,grep 有一个调用 grep -E 命令的快捷方式:egrep。它使用正则表达式来替代模式去匹配,这样就为我们提供了一个更为强大的方式来搜索文本。
除了我们在第 3 节 “Shell 通配符”中提到的通配模式之外,以下介绍一些额外的正则表达式:
可供选择的字符集合还有很多,请参看 egrep(1)。上述只是其中最为常用的。
把某个正则表达式放在圆括号中就可以在后面引用它。比如,表达式 [:alpha:]+
代表某个单词。如果您想要查找出现了两次的单词,您可以把它用圆括号括起来,并且在后面用 \1
来引用它(如果它是第一个待引用组的话)。最多您可以“存储” 9 个这样的组。
$ echo -e "abc def\nabc abc def\nabc1 abc1\nabcdef\nabcdabcd\nabcdef abcef" > testfile $ egrep "([[:alpha:]]+) \1" testfile abc abc def $
返回的那一行仅同由空格分隔的两组相同字符相匹配。其他的同该正则表达式不匹配。
您也可以使用 |
运算符连接两个正则表达式,其结果或是同 |
左边的正则表达式匹配,或是同其右边的正则表达式匹配。对上述 testfile
文件,您可以试着构造一个正则表达式与其中的两次重复出现的单词或是两次重复出现的字母数字组合匹配。
$ egrep "([[:alpha:]]+) \1|([[:alpha:][:digit:]]+) \2" testfile abc abc def abc1 abc1 $
请注意,对于第二组圆括号括起的待引用组,必须使用 \2
来引用,否则将不会得到期望的结果。对于上述要求,更有效的表达式是:
$ egrep "([[:alnum:]]+) \1" testfile abc abc def abc1 abc1 $
最后,要匹配某些特殊字符必须对它们进行转码:在它们前面添加反斜杠。这些字符有:?
、+
、{
、|
、(
、)
以及 \
。它们分别与下列相匹配:\?
、\+
、\{
、\|
、\(
、\)
和 \\
。
所有工具中的正则表达式均遵从上述规则,或是非常类似。花点时间来理解它们将会有助于您使用其他工具(比如 sed)。sed 可以操纵文本,使用正则表达式来改变它们等等。
wc 命令(Word Count (单词计数))用于统计文件中的行数、字符串和单词的数量。它还可用于计算最长行的长度。其语法为:
wc [选项] [文件]
wc 命令默认情况下会打印行数、单词数和字符数。下面是一些例子:
$wc -l /etc/passwd
$grep "model name" /proc/cpuinfo |wc -l
在上一节中,我们得到了成功发送到列于 ./patterns.txt
文件中的电子邮件地址的邮件列表。如果我们想要知道一共有多少封邮件,那么可以将过滤结果通过管道重定向到 wc 命令:
# fgrep -f ./patterns.txt /var/log/mail/info | wc -l
下面列出了这一强大工具的语法[26]:
sort [选项] [文件]
现在我们来考虑一下对 /etc/passwd
文件进行排序。正如您看到的,这个文件并未经过排序:
$ cat /etc/passwd
$ sort /etc/passwd
默认情况下,sort 命令会按照第一个域(本例中就是 login
)对数据进行升序排序。如果我们想要以降序方式排序,可以使用选项 -r
:
$ sort -r /etc/passwd
每个用户在 /etc/passwd
文件中都有他自己的 UID
。下述命令将按照 UID
域进行升序排序:
$ sort /etc/passwd -t":" -k3 -n
$ sort /etc/passwd -t":" -k3 -n -r
$ sort /etc/passwd -t":" -k3 -n |tail -n1
我们先是对 /etc/passwd
文件按 UID
进行了升序排序,然后将结果通过管道传送给 tail 命令,它会输出排序列表的最后一行。