Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目

问题解决
该题目需要将 words.txt
的内容进行统计个数,并且按照降序排序
the day is sunny the
the the sunny is is
方案1
想法
如果能够将文中单词遍历出来,将单词作为key存入map,次数为map的值,这样只需要遍历map不就可以解决该问题了么
实践
要将单词作为key存入map,需要先将单词分割开来
脚本
执行结果
# bash shell_192.sh
the
day
is
sunny
the
the
the
sunny
is
is
#
存入map,并且对结果进行排序
#!/bin/bash
# 定义 map
declare -A dict
# 遍历数据, 填充 map
while read line
do
for xx in $line
do
dict[$xx]=`expr ${dict[$xx]} + 1`
done
done < words.txt
# 打印 map 中的数据
for key in ${!dict[*]}
do
echo -e "$key ${dict[$key]}"
done | sort -k 2 -rn
结果
# bash shell_192.sh
the 4
is 3
sunny 2
day 1
#
方法2
想法
既然上诉我们已经将单词给分割开来了,那么能否用命令uniq
去统计次数呢
实践
先对文章单词进行排序
while read line; do for xx in $line; do echo $xx; done; done < words.txt | sort
结果
day
is
is
is
sunny
sunny
the
the
the
the
然后对文章单词进行数据统计(uniq)
while read line; do for xx in $line; do echo $xx; done; done < words.txt | sort | uniq -c
结果
我们的结果是 单词在前 次数在后,所以还需要 awk
进行输出
while read line; do for xx in $line; do echo $xx; done; done < words.txt | sort | uniq -c | awk '{print $2 " " $1}'
结果
然后再对第二行进行排序
while read line; do for xx in $line; do echo $xx; done; done < words.txt | sort | uniq -c | awk '{print $2 " " $1}' | sort -k 2 -rn
结果
能不能将 while read line; do for xx in $line; do echo $xx; done; done < words.txt
转化为命令呢
sed 's# #\n#g' words.txt | sort | uniq -c | awk '{print $2 " " $1}' | sort -k 2 -rn
但是提交失败了。。。
失败用例

emmm ,原来有些单词间隔有 多个空格,修改下
在 sed 后面 将 空行 排除掉即可
sed 's# #\n#g' words.txt | grep -v '^$' | sort | uniq -c | awk '{print $2 " " $1}' | sort -k 2 -rn
再次提交,正常了
方法3
想法
既然 bash 脚本能够编写并且通过测试,那么 使用 awk 脚本,能否可以呢?
使用awk将单词分割开来
gawk '
{
for (i=1;i<=NF;i++) {
print ($i)
}
}' words.txt
结果
the
day
is
sunny
the
the
the
sunny
is
is
使用数组统计次数,和 方案1 的脚本有异曲同工之处,只不过 awk 是放在数组里面
脚本
gawk '
{
for (i=1;i<=NF;i++) {
S[$i]=S[$i]+1
}
}
END {
for (a in S) {
print (a,S[a])
}
}
' words.txt | sort -rn -k 2
结果
技术细节探寻
以 words.txt
文件为例
对文件进行按行读取
方法1
cat words.txt | while read line
do
...
done
方法2
while read line
do
...
done < words.txt
方法1 的弊端: 当脚本遇到 管道符 |
会开启一个子shell
进行执行,导致的结果是 方法1 中的变量 更改,在循环后就失效了。
bash map
map 和 数组 不同,需要先 申请,在使用
使用 declare -A
申请
获取单个map值
${mapName[key]}
获取所有key
${!mapName[@]}
获取所有值
${mapName[@]}
获取map长度
${#mapName[@]}
awk
变量 NF
是长度
数组可以直接使用,不用预先申请
其他命令
grep -v '^$'
-v: 取反
'^′:代表以什么开头': ^代表以什么开头 ′:代表以什么开头代表以什么结尾,连接起来则为 空行的意思
uniq -c
-c: 统计次数
sort -k 2 -rn
-k: 以多少行进行排序
-r: 降序排序
-n: 依照数字大小排序