工作中经常有需要写一个简单shell脚本的情景,每次都要花费一些时间来用啥学啥,加起来用掉很多时间,所以打算用shell刷一些题,来锻炼自己的shell能力~
写一个 bash 脚本以统计一个文本文件 words.txt 中每个单词出现的频率。
为了简单起见,你可以假设:
words.txt只包括小写字母和 ’ ’ 。
每个单词只由小写字母组成。
单词间由一个或多个空格字符分隔。
当成一个题目来看的话,最先想到就直接map就结束了,搜索后学习了一波map的用法,但是这里map不会按照value把key排序,所以加了个桶排,实现起来很蠢,对,我很蠢~
#!/bin/bash
declare -A map
declare -A rmap
words=$(cat ./words.txt)
for i in $words
do
map[$i]=$((${map[$i]}+1))
done
for i in ${!map[@]}
do
rmap[${map[$i]}]=$i
done
for i in $(seq 10000 -1 1)
do
if [ "${rmap[$i]}" != "" ];
then
echo ${rmap[$i]} $i
fi
done
首先用tr命令去掉文本中多余的空格和换行符,之后对整个文本sort,用uniq -c 来去重并展示出现次数。
之后再按照数值sort一次用awk换列输出即可。
cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -r | awk '{print $2 " " $1}'
1. for 循环 1 - 10
for i in $(seq 1 10)
do
echo $i
done
2. for 循环 10 - 1
其实增序for循环时隐藏了一个变量 1 ,所以降序时加上-1即可。
for i in $(seq 10 -1 1)
3. if 语句
if [ command ]; then
#符合该条件执行的语句
elif [ command ]; then
#符合该条件执行的语句
else
#符合该条件执行的语句
fi
4. 字符串判等
[ "$a" == "$b" ]
5. 字符串判空
[ "$a" == "" ]
declare 用来给变量 声明/取消声明 某个属性。
declare [+/-][选项] 变量名
选项:
-:给变量舍得类型属性
+:取消变量的类型属性
-a:将变量声明为数组型
-a: 将变量声明为map型
-i:将变量声明为整型
-x:将变量声明为环境变量
-r:将变量声明为只读变量
-p:查看变量的被声明的类型
1. 声明变量a为 map
declare -A a
2. 遍历整个map
for i in ${!map[@]}
do
echo $i
done
3. 使用map的value值
${map[$key]}
Linux tr 命令用于转换或删除文件中的字符。
tr 指令从标准输入设备读取数据,经过字符串转译后,将结果输出到标准输出设备。
tr [OPTION]…SET1[SET2]
-c, --complement:反选设定字符。也就是符合 SET1 的部份不做处理,不符合的剩余部份才进行转换
-d, --delete:删除指令字符
-s, --squeeze-repeats:缩减连续重复的字符成指定的单个字符
-t, --truncate-set1:削减 SET1 指定范围,使之与 SET2 设定长度相等
–help:显示程序用法信息
–version:显示程序本身的版本信息
1. 将a.txt中所有的a替换成b
cat a.txt | tr 'a' 'b'
2. 将a.txt中所有的a替换成b,c替换成d
cat a.txt | tr 'ab' 'cd'
3. 将a.txt中所有小写字母替换成对应的大写字母
cat a.txt | tr a-z A-Z
4. 合并 a.txt中所有连续的空格及换行
cat a.txt | tr -s ' ' '\n'
5. -t的使用,使SET1长度和SET2相等,例如下面的效果是把a.txt中所有a替换成b.
因为SET1的长度被限制为与SET2相等。
cat a.txt | tr -t 'ac' 'b'
用法:sort [选项]… [文件]…
串联排序所有指定文件并将结果写到标准输出。
排序选项:
-b, --ignore-leading-blanks 忽略前导的空白区域
-d, --dictionary-order 只考虑空白区域和字母字符
-f, --ignore-case 忽略字母大小写
-g, --general-numeric-sort 按照常规数值排序
-i, --ignore-nonprinting 只排序可打印字符
-n, --numeric-sort 根据字符串数值比较(整个字符串的字典序)
-r, --reverse 逆序输出排序结果
其他选项:
-c, --check, --check=diagnose-first 检查输入是否已排序,若已有序则不进行操作
-k, --key=位置1[,位置2] 在位置1 开始一个key,在位置2 终止(默认为行尾)
-m, --merge 合并已排序的文件,不再进行排序
-o, --output=文件 将结果写入到文件而非标准输出
-t, --field-separator=分隔符 使用指定的分隔符代替非空格到空格的转换
-u, --unique 配合-c,严格校验排序;不配合-c,则只输出一次排序结果
sort的单位是每一行。
将a.txt中的每一行按照字典序排序
cat a.txt | sort
将a.txt中的每一行,按照常规数字排序,支持科学计数法
cat a.txt | sort -g
将a.txt中的每一行排序并去重
cat a.txt | sort -u
uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。
-c: 在每列旁边显示该行重复出现的次数。
-d: 仅显示重复出现的行列,显示一行。
-D: 显示所有重复出现的行列,有几行显示几行。
-u: 仅显示出一次的行列
-i: 忽略大小写字符的不同
-f Fields: 忽略比较指定的列数。
-s N: 忽略比较前面的N个字符。
-w N: 对每行第N个字符以后的内容不作比较。
对a.txt文本直接去重
cat a.txt | uniq
对a.txt文本去重后旁边显示出现次数
cat a.txt | uniq -c
awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,…以此类推。
$NF是number finally,表示最后一列的信息,跟变量NF是有区别的,变量NF统计的是每行列的总数
用途 | 输入文本 a.txt | 命令 | 输出文本 |
---|---|---|---|
筛选包含关键字的行 | a b c c d f b a g |
awk ‘/b/’ a.txt | a b c b a g |
筛选包含关键字的行 并输出某一列 |
a b c c d f b a g |
awk ‘/b/ {print $2}’ a.txt | b a |
使用printf输出,更清晰 | a b c c d f b a g |
awk ‘/b/ {printf ("%s\n",$2)}’ a.txt | b a |
只保留第二行信息 | a b c c d f b a g |
awk ‘NR==2 {printf ("%s",$2)}’ a.txt | c d f |
设置特定的分隔符并输出第一列 | a : b : c c : d : f b : a : g |
awk -F ‘:’ ‘{printf ("%s",$2)}’ a.txt | b d a |
设置特定的分隔符并输出最后一列 | a : b : c c : d : f b : a : g |
awk -F ‘:’ ‘{printf ("%s",$NF)}’ a.txt | c f g |
设置特定的分隔符并输出倒数第二列 | a : b : c c : d : f b : a : g |
awk -F ‘:’ ‘{printf ("%s",$NF-1)}’ a.txt | b d a |
获取第二到第三行的第一列信息 | a : b : c c : d : f b : a : g |
awk -F ‘:’ ‘{if(NR>=2&&NR<=3) print $1}’ a.txt | c b |
多个分隔符 | 1:2?3,4 | awk -F ‘[,:?]’ ‘{print $4}’ words.txt | 4 |