今天去了一家公司面试,而面试题的最后一道题是:找出Apache的access.log中所有的独立IP,并统计显示出top 10的IP。
而我的做法是:
grep ‘[1,3]\.[1,3]\.[1,3]\.[1,3] | cut -d ‘.’ -f 0-3 | uniq | cat -n 10
而这个写的想法是:用grep算出所有有IP的行,再cut成只有IP,用uniq进行统计, 然后打印出10行。grep暂且不说了,根本就是错的,先来说下uniq吧,我之前还怀疑这个命令是不是用来统计用,刚才查了下资料,才知道uniq是以下的用法:
uniq: 检查及删除文本文件中重复出现的行列。
uniq [-cdu][-f<栏位>][-s<字符位置>][-w<字符位置>][--help][--version] [输入文件][输出文件]
说明:uniq可检查文本文件中重复出现的行列。
参 数:
-c或–count 在每列旁边显示该行重复出现的次数。
-d或 –repeated 仅显示重复出现的行列。
-s<字符位置>或–skip-chars=<字符位置> 忽略比较指定的字符。
-u 或–unique 仅显示出一次的行列。
– n 前n个字段与每个字段前的空白一起被忽略。一个字段是一个非空格、非制表符的字符串,彼此由制表符和空格隔开(字段从0开始编号)。
+n 前n个字符被忽略,之前的字符被跳过(字符从0开始编号)。
- f n 与- n相同,这里n是字段数。
- s n 与+n相同,这里n是字符数。
例子:
1. 显示文件example中不重复的行。
uniq – u example
2. 显示文件example中不重复的行,从第2个字段的第2个字符开始做比较。
uniq – u – 1 +1 example
而面试官给出的结果是使用sort来进行统计,下面就来说下sort的用法:
sort 命令是对指定的文件中的行进行排序,并将结果写到标准输出。如果指定了多个文件,那么 sort 命令将这些文件连接起来,并当作一个文件进行排序。-(减号)代替文件名指定标准输入。如果您不指定任何文件名,那么该命令对标准输入排序。可以使用 -o 标志指定输出文件。
如果不指定任何标志,sort 命令基于当前语言环境的整理顺序对输入文件的所有行排序。
主要参数
-A 使用 ASCII 整理顺序代替当前语言环境的整理顺序在逐字节的基础上排序。
-b 忽略前导空格和制表符,找出字段的第一或最后列。
-c 检查输入是否已按照标志中指定的排序规则进行排序。如果输入文件排序不正确,就返回一个非零值。
-d 使用字典顺序排序。比较中仅考虑字母、数字和空格。
-f 比较前将所有小写字母改成大写字母。
-i 比较中忽略所有非显示字符。
-k KeyDefinition 指定排序关键字。KeyDefinition 选项的格式为: [ FStart [ .CStart ] ] [ Modifier ] [ , [ FEnd [ .CEnd ] ][ Modifier ] ]排序关键字包括所有以 FStart 变量指定的字段和 CStart 变量指定的列开头的字符及以 FEnd 变量指定的字段和 CEnd 变量指定的列结束的字符。Modifier 变量的值可以是 b、d、f、i、n 或 r。修饰符与同一字母的标志等价。
-m 只合并多个输入文件;假设输入文件已经排序。
-n 按算术值对数字字段排序。数字字段可包含前导空格、可选减号、十进制数字、千分位分隔符和可选基数符。对包含任何非数字字符的字段进行数字排序会出现无法预知的结果。
-o OutFile 将输出指向 OutFile 参数指定的文件,而不是标准输出。OutFile 参数值可以与 File 参数值相同。
-r 颠倒指定排序的顺序。
-t Character 指定 Character 为单一的字段分隔符。
-u 禁止按照排序关键字和选项的所有等同排序(每一组行中一行除外)。
-T Directory 将创建的所有临时文件放入 Directory 参数指定的目录中。
-y[Kilobytes] 用 Kilobytes 参数指定的主存储的千字节数启动 sort 命令,并根据需要增加存储量。(如果 Kilobytes 参数指定的值小于最小存储站点或大于最大存储站点,就以这个最小存储站点或最大存储站点取代)。如果省略 -y 标志,sort 命令以缺省的存储大小启动。-y0 标志用最小存储启动,而 -y 标志(不带 Kilobytes 值)用最大存储启动。sort 命令使用的存储量显著地影响性能。以大存储量对小文件排序将很浪费。
-z RecordSize 如果正在排序的任一行大于缺省的缓冲区大小,要防止出现异常终止。指定 -c 或 -m 标志时,省略排序阶段,使用系统的缺省缓冲大小。如果已排序行超出这一大小,排序异常终止。-z 选项指定排序阶段最长行的记录,因而可在合并阶段分配足够的缓冲区。RecordSize 必须指明等于或大于要合并的最长行的字节值。
例子
要在 LC_ALL、LC_COLLATE 或 LANG 环境变量设置为 En_US 的情况下排序 fruits 文件,请输入:
LANG=En_US sort fruits此命令序列显示以升序词典顺序排序的 fruits 文件的内容。每一列的字符,包括空格、数字和特殊字符都经一一比较。 例如,如果 fruits 文件包含文本:bananaorangePersimmonapple%%bananaappleORANGEsort 命令显示:%%bananaORANGEPersimmonappleapplebananaorange在 ASCII 整理序列中,%(百分号)在大写字母前,大写字母在小写字母前。如果您当前的语言环境指定 ASCII 之外的字符集,结果可能不同。
要以字典顺序排序,请输入:
sort -d fruits此命令序列排序和显示 fruits 文件的内容,并且只比较字母、数字和空格。如果 fruits 文件与示例 1 相同,那么 sort 命令显示: ORANGEPersimmonappleapple%%bananabananaorange-d 标志忽略 %(百分号)字符,因为它不是个字母、数字或空格。(即 %%banana 被 banana 取代)。
要将包含大写字母和具有类似小写行的特殊字符行分组,请输入:
sort -d -f fruits
-d 标志忽略特殊字符,-f 标志忽略大小写差异。将 LC_ALL、LC_COLLATE 或 LANG 环境变量设置为 C 的情况下,fruits 文件的输出结果变为: appleapple%%bananabananaORANGEorangePersimmon
要除去重复行排序,请输入:
sort -d -f -u fruits
-u 标志告诉 sort 命令除去重复的行,使文件中的每一行唯一。此命令序列显示: apple%%bananaORANGEPersimmon不仅除去重复的 apple,而且也除去了 banana 和 ORANGE。除去这些是因为 -d 标志忽略 %% 这个特殊字符,-f 标志忽略大小写差异。
要如上面那样排序,除去重复的实例(除非是大写字母或标点不同),请输入:
sort -u +0 -d -f +0 fruits输入 +0 -d -f 完成的排序与示例 3 中 -d -f 的排序类型相同,+0 进行另一项比较以区分不一样的行。这防止 -u 标志将它们除去。 示例 1 所示的 fruits 文件中,添加的 +0 将 %%banana 与 banana 及 ORANGE 与 orange 区分开来。然而,apple 的两个实例是相同的,所以其中之一被删除。apple%%bananabananaORANGEorangePersimmon
要指定分隔字段的字符,请输入:
sort -t: +1 vegetables
此命令序列排序 vegetables 文件,对每一行上第一个冒号后的文本进行比较。+1 告诉 sort 命令忽略第一字段,从第二字段的开始到该行的结束进行比较。-t: 标志告诉 sort 命令冒号分隔字段。
如果 vegetables 包含:
yams:104turnips:8potatoes:15carrots:104green beans:32radishes:5lettuce:15那么,将 LC_ALL、LC_COLLATE 或 LANG 环境变量设置为 C 的情况下,sort 命令将显示:carrots:104yams:104lettuce:15potatoes:15green beans:32radishes:5turnips:8注意数字没有按照数字排序。当用字典式分类从左至右比较每一个字符时出现这种情况。换句话说,3 在 5 之前,所以 32 在 5 之前。
要排序数字,请输入:
sort -t: +1 -n vegetables
此命令序列按照第二个字段对 vegetables 文件进行数字排序。如果 vegetables 文件与示例 6 中的相同,那么 sort 命令将显示: radishes:5turnips:8lettuce:15potatoes:15green beans:32carrots:104yams:104
要对多个字段排序,请输入:
sort -t: +1 -2 -n +0 -1 -r vegetables或 sort -t: -k2,2 n -k1,1 r vegetables
此命令序列对第二字段(+1 -2 -n)进行数字排序。在这个顺序中,它以逆字母顺序(+0 -1 -r)对第一字段排序。将 LC_ALL、LC_COLLATE 或 LANG 环境变量设置为 C 的情况下,输出将类似于: radishes:5turnips:8potatoes:15lettuce:15green beans:32yams:104carrots:104
此命令按数字顺序对行排序。当两行数字相同时,它们以逆字母顺序出现。
要使用排序的文本替换原始文件,请输入:
sort -o vegetables vegetables此命令序列将排序输出存入 vegetables 文件( -o vegetables)。
还有就是最后的cat了,面试官的用法就是使用head, 他说cat是无法通过管道进行输出打印的,因些使用了head.
今天真的丢到家了啊!
补: 看了上面的资料后,我得到的修改了答案,下面是答案,主要是修改了最后一部份:
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' access.log | uniq -cd | sort | head -n 10
希望这次的修改可以减轻我面试过程的错误程度!
注:我今天终于知道怎样去获取一个IP了,现在以用ifconfig 为例吧:
ifconfig re0 | grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\} | cut -d ' ' -f 2
or
ifconfig re0 | awk '/inet addr/{ gsub("inet", "", $2); print $2'
grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}
这一段主要是检索出有IP的一行。
cut -d ' ' -f 2
这里是提取检索出来有IP的一行的第二个字段,也就是IP了。