这里以kevin.txt文件内容(单词由一个或多个空格字符分隔)为例进行简单说明
[root@centos6-test06 ~]# cat /root/kevin.txt
the world kevin is the
is world grace the kevin
art the kevin the is kevin
统计kevin.txt文件中出现的单词次数
第一种方法:结合grep和awk编写shell脚本
脚本内容如下:
[root@centos6-test06 ~]# cat count.sh
#! /bin/bash
# solution 1
if [ $# -eq 0 ]
then
echo "Usage:$0 args error"
exit 0
fi
if [ $# -ge 2 ]
then
echo "analyse the first file $1"
fi
#get the first file
filename=$1
grep -E -o "\b[[:alpha:]]+\b" $filename | awk ' { count[$0]++ }
END{printf("%-20s%s\n","Word","Count");
for(word in count)
{printf("%-20s%s\n",word,count[word])}
}'
=======================================================================
脚本参数说明:
-eq: 等于
-ne: 不等于
-le: 小于等于
-ge: 大于等于
-lt: 小于
-gt: 大于
\b backspace,printf参数
awk说明
awk由内容和动作组成;awk pattern {action}
pattern可以是BEGIN、END、expression
可以执行 for ( var in array ) statement
1)BEGIN模块:这个模块包括了一个操作块(也就是"{ }"内的内容)。该操作块是在文件输入之前执行的,也就是不需要输入任何文件数据,也能执行该模块。
BEGIN模块常用于设置修改内置变量如(OFS,RS,FS等),为用户自定义的变量赋初始值或者打印标题信息等。
BEGIN模块中的语句操作以":"标志或者分行隔开。
比如:
[root@centos6-test06 ~]# awk 'BEGIN{print "Hello World! Begin doing!"}'
Hello World! Begin doing!
2)END模块:与BEGIN模块相反,是处理完文件后的操作。不匹配任何输入行,常用于输出一些总结信息。
3)匹配表达式:
[[:alpha:]] 代表字母
[[:alnum:]] 代表字母与数字字符
[a-zA-Z0-9] 代表单个字母和数字字符
匹配到/root/kevin.txt中所有的单词
[root@centos6-test06 ~]# grep -E "\b[[:alpha:]]+\b" /root/kevin.txt
把匹配到的单词每行1个打印出来
[root@centos6-test06 ~]# grep -E -o "\b[[:alpha:]]+\b" /root/kevin.txt
能匹配到整个单词
"\b[[:alpha:]]+\b"
=======================================================================
开始统计:
[root@centos6-test06 ~]# /bin/bash count.sh /root/kevin.txt
Word Count
world 2
art 1
the 5
grace 1
is 3
kevin 4
第二种方法:使用grep匹配表达式
[root@centos6-test06 ~]# grep -E -o "\b[[:alpha:]]+\b" /root/kevin.txt|sort|uniq -c|sort -rn
5 the
4 kevin
3 is
2 world
1 grace
1 art
第三种方法:使用awk匹配表达式
[root@centos6-test06 ~]# awk -F' ' '{for(i=1;i<=NF;i=i+1){print $i}}' /root/kevin.txt |sort|uniq -c|sort -nr|awk -F' ' '{printf("%s %s\n",$2,$1)}'
the 5
kevin 4
is 3
world 2
grace 1
art 1
通常,awk逐行处理文本。awk每接收文件的一行,然后执行相应的命令来处理。
找到指定单词,自定义变量count自增,最后输出语句和count值
sort: 把各行按首字母排列顺序重新排列起来
sort -nr: 每行都以数字开头,按数字从达到小,排列各行
uniq -c: 统计各行出现的次数,并把次数打印在每行前端
NF: 浏览记录的域的个数
例如;
搜索统计单词"kevin"的个数
[root@centos6-test06 ~]# awk -F : '/kevin/{count++} END{print "the count is ",count}' /root/kevin.txt
the count is 3
第四种方式:统计kevin.txt文件中的单词个数,并指定排名个数(利用管道组成的一条命令)
写一个shell脚本,查找kevin.txt文本中n个出现频率最高的单词,输出结果需要显示单词出现的次数,并按照次数从大到小排序。分为以下几步:
1)将文本文件以一行一个单词的形式显示出来;
2)将单词中的大写字母转化成小写字母,即Word和word认为一个单词;
3)对单词进行排序;
4)对排序好的单词列表统计每个单词出现的次数;
5)最后显示单词列表的前n项。
[root@centos6-test06 ~]# cat tr.sh
#!/bin/bash
#查找文本中n个出现频率最高的单词
count=$1 #$1是输出频率最高单词的个数
cat $2 | #$2是目标文本文件名称也可是是字符串
tr -cs "[a-z][A-Z][0-9]" "\n" | #tr是sed的简化,-c用前字符串中字符集的补集替换成后字符串即将不是字符和数字的单词替换换行
#-s删除所有重复出现换行,只保留第一个
#可以写成tr -cs "[a-z][A-Z][0-9]" "\012"或tr -cs "[a-z][A-Z][0-9]" "[\012*]"
tr A-Z a-z | #将大写字母换化为小写字母
sort | #对单词进行排序
uniq -c | #删除文本文件中重复出现的行,-c在每列旁边显示该行重复出现的次数
sort -k1nr -k2 | #字符串以空格分成域,先按第一个域排序,在按第二个域排序
#-k1指定第一个域,-n按数字大写排序,-r排序结果逆向显示
head -n $count #显示前n行
取kevin.txt文件中出现频率最高的1个单词
[root@centos6-test06 ~]# sh tr.sh 1 /root/kevin.txt
5 the
取kevin.txt文件中出现频率最高的2个单词
[root@centos6-test06 ~]# sh tr.sh 2 /root/kevin.txt
5 the
4 kevin
取kevin.txt文件中出现频率最高的3个单词
[root@centos6-test06 ~]# sh tr.sh 3 /root/kevin.txt
5 the
4 kevin
3 is
为便于理解可在shell命令行下将管道分解,可以举如下一例,将输出的内容中的单词单个一行打印出来
[root@centos6-test06 ~]# echo "kevin is a good boy come on baby" | tr -cs "[a-z][A-Z][0-9]" "\n"
kevin
is
a
good
boy
come
on
baby
总结
1)sort -k2第二个域会按字母顺序对单词进行排序,字母以a开头的单词在以z开头的单词后面。
2)上述一条简单的命令综合应用了tr、sort、uniq、head等文本处理命令,显示shell工具在文本处理方面的强大。