题目:
写一个 bash 脚本以统计一个文本文件 words.txt 中每个单词出现的频率。
为了简单起见,你可以假设:
words.txt只包括小写字母和 ' ' 。
每个单词只由小写字母组成。
单词间由一个或多个空格字符分隔。
示例:
假设 words.txt 内容如下:
the day is sunny the the
the sunny is is
你的脚本应当输出(以词频降序排列):
the 4
is 3
sunny 2
day 1
说明:
不要担心词频相同的单词的排序问题,每个单词出现的频率都是唯一的。
你可以使用一行 Unix pipes 实现吗?
解题方法:
awk '{for(n=1;n<=NF;n++){word[$n]++}} END{for(i in word){print i,word[i]}}' words.txt | sort -nr -k2
要看懂上面的解题方法,需要明白的是:
1、awk是个行编辑器,这个相当重要。
2、在awk中,当字符串或者空字符串参与数值运算时,都会被当做0参与运算,比如:
[root@syztoo ~]# awk 'BEGIN{a=""; a=a+1; print a}' test.txt
1
3、在awk中,当引用数组中一个不存在的元素时,awk会自动创建这个元素,并为其赋值为空字符串,比如:
[root@syztoo ~]# awk 'BEGIN{print arr[a]; arr[a]++; print arr[a]}' test.txt
1
# 第一次引用数组不存在的元素,所以赋值为空字符串;第二次将空字符串当做0参于数值运算,所以打印1
4、在awk中,NF表示按分隔符分隔后的列数,$n表示当前行的第n列内容,所以:
for(n=1;n<=NF;n++){word[$n]++}}
# 表示遍历当前行的每一个字段,同时将字段作为word数组的索引,进行存储,并做累加计算
# 比如行内容为:the sunny is is
# 那么经过上面代码处理后,word数组存储的是:word[the]=1,word[sunny]=1,word[is]=2
5、END { } 表示所有行处理完以后,需要执行的代码块,这里:
END{for(i in word){print i,word[i]}}
# 上面代码是打印数组的索引和数组元素,i为索引,word[i]为元素
6、sort命令:
选项:
-n 表示按数值排序,从小到大
-r 表示反转排序顺序
-k 后面跟一个数字,表示按第几列内容进行排序
-t 指定分隔符,不指明-t时,表示默认按一个空格分隔