shell 编程实例
需求:写一个 bash 脚本以统计一个文本文件 words.txt 中每个单词出现的频率。
为了简单起见,你可以假设:
words.txt只包括小写字母和 ' ' 。
每个单词只由小写字母组成。
单词间由一个或多个空格字符分隔。
来源:力扣(LeetCode)
题目链接:https://leetcode-cn.com/problems/word-frequency
脚本代码:
awk '{for(i=1;i<=NF;i++){asso_array[$i]++;}};END{for(w in asso_array){print w,asso_array[w];}}' world.txt
简单解释:
awk是一种编程语言,主要用于在linux/unix下对文本和数据进行处理,是linux/unix下的一个工具。数据可以来自标准输入、一个或多个文件,或其它命令的输出。
awk的处理文本和数据的方式:逐行扫描文件,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。
基本格式为:
awk 选项 '命令部分' 文件名
特别说明:
引用shell变量需用双引号引起
想了解更多关于awk的请点击这里
首先明确awk是按行处理,即每次处理一行数据,处理完后继续处理下一行数据。
这里选项部分默认为空格为分隔符。
命令部分格式为 'BEGIN{awk语句};{处理中};END{awk语句}'
①BEGIN:表示在程序开始前执行。
②END :表示所有文件处理完后执行。
③用法:‘BEGIN{开始处理之前};{处理中};END{处理结束后}’。
这里还用涉及到shell编程中关联数组的概念,关联数组我们可以简单的当成一个字典来看。(关联数组在这里爱点不点吧!)
{for(i=1;i<=NF;i++){asso_array[$i]++;}},这行命令表示从某一行的第一列开始处理,(NF表示每一行的列数),以分割的每一个字符串为下标(索引),存储的是字符串出现的次数,用一个循环遍历所有行,得到一个以字符串为下标,字符串出现的次数为值得关联数组,处理结束后输出内容即可。
需求2:给定一个包含电话号码列表(一行一个电话号码)的文本文件 file.txt,
写一个 bash 脚本输出所有有效的电话号码。你可以假设一个有效的电话号码必须
满足以下两种格式: (xxx) xxx-xxxx 或 xxx-xxx-xxxx。(x 表示一个数字)
来源:力扣(LeetCode)
链接:题目链接
测试文件grep.txt里写入以下内容
用正则表达式进行筛选:
grep -P ‘^([0-9]{3}-|([0-9]{3}) )[0-9]{3}-[0-9]{4}$’ file.txt
解析:此问题采用grep+正则表达式来解决
grep -P '^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$' grep.txt
解析:grep支持正则表达式,但是只支持一般得正则表达式,-P表示采用扩展的正则表达式,
这里要区分一下(),[],{},这三个是正则表达式中的特殊字符,要想表示原来的字符得用’\'进行转义。
() 是为了提取匹配字符串的,表达式中有几个()就有几个相应的匹配字符串
(\s*)表示连续空格的字符串
[] 是定义匹配的字符范围。比如[a-zA-Z0-9]表示相应位置的字符要匹配英文字符和数字。[\s表示空格或者号]
{}一般是用来匹配的长度。比如\s{3}表示匹配三个空格,\s[1,3]表示匹配1到3个空格
(0-9)匹配’0-9’本身。[0-9]匹配数字(注意后面有,可以为空)[0-9]+匹配数字(注意后面有+,不可以为空),
{0-9}写法是错误的
[0-9]{0,9}表示长度为0到9的数字字符串。
题目解析地址
题目三:
题目来源:https://leetcode-cn.com/problems/transpose-file/
要求:给定一个文件 file.txt,转置它的内容。
你可以假设每行列数相同,并且每个字段由 ’ ’ 分隔.
示例:
假设 file.txt 文件内容如下:
name age
alice 21
ryan 30
应当输出:
name alice ryan
age 21 30
解析来源:https://leetcode-cn.com/problems/transpose-file/solution/awkming-ling-yong-shu-zu-chu-cun-dai-shu-chu-jie-g/
awk是一行一行地处理文本文件,运行流程是:
先运行BEGIN后的{Action},相当于表头
再运行{Action}中的文件处理主体命令
最后运行END后的{Action}中的命令
有几个经常用到的awk常量:NF是当前行的field字段数;NR是正在处理的当前行数。
注意到是转置,假如原始文本有m行n列(字段),那么转置后的文本应该有n行m列,即原始文本的每个字段都对应新文本的一行。我们可以用数组res来储存新文本,将新文本的每一行存为数组res的一个元素。
在END之前我们遍历file.txt的每一行,并做一个判断:在第一行时,每碰到一个字段就将其按顺序放在res数组中;从第二行开始起,每碰到一个字段就将其追加到对应元素的末尾(中间添加一个空格)。
文本处理完了,最后需要输出。在END后遍历数组,输出每一行。注意printf不会自动换行,而print会自动换行。
awk '{
for (i=1;i<=NF;i++)
{
if (NR==1){
res[i]=$i
}
else
{
res[i]=res[i]" "$i
}
}
}END{
for(j=1;j<=NF;j++){
print res[j]
}
}' file.txt
作者:gao-si-huang-bu
链接:https://leetcode-cn.com/problems/transpose-file/solution/awkming-ling-yong-shu-zu-chu-cun-dai-shu-chu-jie-g/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。