使用 uniq 进行计数
UNIX 类操作系统最伟大的特性之一是它们能够组合多个命令。 通过组合命令,您可以执行各种各样的任务,唯一的限制是您的聪明才智和想象力。
尽管潜在的命令组合数量巨大,但我的经验表明,某些组合比其他组合更常用。 我经常使用的一种组合是组合 sort 和 uniq 命令来计算文件中任意字符串的出现次数。 对于新的 Linux 用户来说,这是一个很棒的技巧,您永远不会后悔将其添加到您的技能库中。
您可以像这样发现每个单词出现的次数:
% sort fruit | uniq -c 1 oranges 2 apples
这里发生了什么? 首先,sort fruit对文件进行排序。 结果通常会转到标准输出(在本例中是您的终端),但请注意后面的 |(管道)。 该管道将以下命令的输出定向到sort fruit下一个命令的输入,即uniq -c,它打印每一行,并在前面加上该行出现的次数。
从简单的例子中看不出为什么这如此强大。 但是,当手头的文件是 Apache Web 服务器访问日志(包含数十万行)时,这一点变得更加清晰。 访问日志包含大量有价值的信息。 通过使用 sort 和 uniq,您可以从命令行动态地进行令人惊讶的简单数据分析。 想象一下,一位同事迫切需要知道在一月份请求名为 foo.php 的 PHP 脚本次数最多的前十个 IP 地址。 片刻之后,您就拥有了她需要的信息。 您是如何如此快速地推导出这些信息的? 让我们逐步看看解决方案。
为了便于说明,您的服务器以以下格式记录日志
192.168.1.100 - - [31/Jan/2004:23:25:54 -0800] "GET /index.php HTTP/1.1" 200 7741
该日志包含来自多个月的数据,而不仅仅是 2004 年 1 月,因此首要任务是使用 grep 来限制我们的数据集
% grep Jan/2004 access.log
然后,我们在输出中查找 foo.php
% grep Jan/2004 access.log | grep foo.php
如果要计算 IP 地址的出现次数,我们最好将输出限制为仅该字段,如下所示
% grep Jan/2004 access.log | grep foo.php | awk '{ print $1 }'
对 awk 的讨论超出了本文的范围。 目前,您只需要了解awk '{ print $1 }'打印每一行上任何空格之前的第一个字符串。 在本例中,它是 IP 地址。
现在,最后,我们可以应用 sort 和 uniq。 这是最终的命令管道
% grep Jan/2004 access.log | grep foo.php | \ awk '{ print $1 }' | sort -n | uniq -c | \ sort -rn | head
反斜杠 (\) 表示该命令在下一行继续。 您可以将该命令键入为没有反斜杠的一长行,或者使用它们将一个长管道分成屏幕上的多行。
您可能已经注意到,与我们的简单示例不同,第一个 sort 是一个数字排序 (sort -n)。 这是合适的,因为我们毕竟是在处理数字。
另一个不同之处是包含了| sort -rn | head。sort -rn命令以相反的数字顺序对以下命令的输出进行排序uniq -c。head命令仅打印输出的前十行。 前十行非常适合手头的任务,因为我们只需要前十个
43 12.175.0.35 16 216.88.158.142 12 66.77.73.85 9 66.127.251.42 7 66.196.72.78 7 66.196.72.28 7 66.196.72.10 7 66.147.154.3 7 192.168.1.1 6 66.196.72.64
您可以通过更改任何组件命令来更改此管道的功能。 例如,如果您想打印最后十个而不是前十个,您只需要更改head为tail.
Brian Tanaka 自 1994 年以来一直担任 UNIX 系统管理员,曾为 The Well、SGI、Intuit 和 RealNetworks 等公司工作。可以通过 btanaka@well.com 与他联系。