正则三剑客
基础正则
Basic Regular Expression, BRE
^ 以……开头
$ 以……结尾
^$ 空行(这一行中没有任何元素)
. 代表任何一个字符(但是不包括空行)
\ 转译符
* 前一个字符连续出现0次或0次以上
.* 所有内容、任意内容(包含空行)
1 | |
[] 匹配指定的任何一个字符
1 | |
拓展正则
Extended Regular Expression, ERE
+ 前一个字符连续出现1次或1次以上
| 或者 比如 ‘qizidog|qizizhou’ 匹配qizidog或者qizizhou(中括号是或者单个字符,竖线是或者两个部分)
() 一般来说有两种用法:被括起来的部分相当于一个整体;后/反向引用
1 | |
{} ‘o{m,n}’ 前一个字母o,至少连续出现了m次,至多连续出现n次(贪婪匹配);’o{m}’ 前一个字母o,恰好连续出现了m次;’o{m,}’ 前一个字母o,至少连续出现了m次;’o{,n}’ 前一个字母o,至多连续出现了n次
? 前一个字符出现了0次或1次
三剑客
三剑客成员
| command | function | 场景 |
|---|---|---|
| grep | 过滤 | 过滤速度很快 |
| sed | 替换、取行 | 需要替换/修改文件内容,取出某个范围的内容 |
| awk | 取列、统计 | 取列、比较、统计计算 |
grep
1 | |
惯用写法:ps -ef | grep 'python' | grep -v grep | wc -l 检查有多少个python后台进程(排除了grep自身的这一个进程),也可以用这种写法 ps -ef | grep '[p]ython' | wc -l,通过一个中括号巧妙地避免了grep的过滤项和自身重名。
举例:取轨迹数据日志的订单id:grep -E '[0-9a-z]{32}' traj-0110.log。
sed
1 | |
示范命令:sed -r 's#oldboy#oldgirl#g' oldboy.txt
sed命令核心功能:增删改查
| 符号 | 功能 |
|---|---|
| p | 显示 print |
| d | 删除 delete |
| cai | 增加 c/a/i |
| s | 替换 substitute |
sed命令执行过程:“找谁干啥”
查找p
| 查找格式 | 功能 |
|---|---|
| ‘1p’ ‘2p’ | 指定行号进行查找。’$p’表示最后一行 |
| ‘1,5p’ | 指定行号范围进行查找。’4,$p’表示从第4行到最后一行 |
| ‘/hello/p’ | 类似于grep过滤,//里面可以写正则 |
| ‘/10:00/,/11:00/p’ | 输出从包含10:00到包含11:00的所有行(找日志常用) |
| ‘2,/hello/p’ | 混合使用,输出从第2行开始到包含hello之间的所有行 |
举例:sed -nE '/18:1[0-9]:[0-9]{2}/,/18:1[0-9]:[0-9]{2}/p' traj-0110.log 找出[18:10, 18:20)范围内的所有日志。
⚠️注意,使用范围查询时,如果起始行找不到匹配,那么无论结束行是否能够被匹配,结果输出都为空(因为没有开始);如果找到了起始行,但没有找到结束行,那么从起始行开始一直到最后的所有内容都会被输出。
删除d
| 删除格式 | 功能 |
|---|---|
| ‘1d’ ‘2d’ | 指定行号进行删除。’$p’表示最后一行 |
| ‘1,5d’ | 指定行号范围进行删除。’4,$p’表示从第4行到最后一行 |
| ‘/hello/d’ | 删除包含hello的行,//里面可以写正则 |
| ‘/10:00/,/11:00/d’ | 删除从包含10:00到包含11:00的所有行(找日志常用) |
| ‘2,/hello/d’ | 混合使用,删除从第2行开始到包含hello之间的所有行 |
删除操作是不会直接修改原始文件的。
举例:删除(不显示)文件中的空行和注释行:
grep -vE '^$|^#' /etc/ssh/ssh_configsed -E '/^$|^#/d' /etc/ssh/ssh_configsed -nE '/^$|^#/!p' /etc/ssh/ssh_config!表示取反,即遇到空行和注释行则不显示输出
增加cai
| 类型 | 功能 |
|---|---|
| c | replace,替代这一行 |
| a | append,在指定行的下一行追加内容 |
| i | insert,在指定行的前一行插入内容 |
举例:向config文件中追加一些配置内容:
cat >> config << 'EOF'这个方法会直接修改原始文件,直接把后面输的内容追加到了文件的最后。
UseDNS no
PermitRootLogin no
EOFsed '$a UseDNS no\nPermitRootLogin no' config$a后面的那一个空格加不加都可以,加上更易读一点。此方法不会修改原始文件,而是将修改的结果输出到屏幕,可以通过重定向来写入新的文件。
替换s
| 替换格式 | 功能 |
|---|---|
| s###g | 中间是三个相同的符号就行,比如3个#、/、2都可以。 井号之间分别放替换前和替换后的内容。 |
g:global全局替换的意思,如果不加g,只会替换第一个满足条件的值。- 后向引用:先保护,再使用。用小括号把要引用的内容括起来,在替换项处再通过
反斜杠+数字来引用。
举例:
- 删除所有的数字:
sed 's#[0-9]##g' traj.log - 将所有的uuid用两个五角星包裹起来:
sed -E 's#([0-9a-z]{32})#⭐️\1⭐️#g' traj.log - 取出指定网卡的ip地址:
ip addr show eth0 | sed -n '3p' | sed -E 's#.*t (.*)/.*#\1#g'其中第一段可以简写为ip a s eth0。ip a s eth0 | sed -nE '3s#.*t (.*)/.*#\1#gp'后两段简写到了一起。
- 取轨迹数据日志的订单id:
sed -nE 's#.*: ([0-9a-z]{32}) .*#\1#gp' traj-0110.log。
⚠️mac中的sed命令是基于BSD的,而linux中的sed是基于GNU的,在mac中使用sed命令的时候需要换行写,体验不怎么样,所以还是装一个GNU的来代替原本的sed比较好。
1 | |
awk
awk语法与c语言类似,是一种处理文本文件的语言,是一个强大的文本分析工具。
awk公式:awk + 选项 + ‘pattern{action}’
使用awk需要了解行和列两个基本的概念:
- 行:record,记录,每一行默认通过回车分割。
- 列:field,字段,每一列默认通过空格、连续空格、制表符分割。
1 | |
示范命令:awk -F, 'BEGIN{print "name"}NR==2{print $2}END{print "end of file"}' oldboy.txt
awk内置变量
| var | 说明 |
|---|---|
| NR | Number of Record 行号 |
| NF | Number of Field 列数 |
| FS | Field Separator 字段分隔符(-F:相当于-v FS=:) |
| OFS | Output Field Separator 输出字段分隔符 |
取行
| 方法 | 说明 |
|---|---|
| NR==1 | 取第一行 |
| NR>=1&&NR<=10 | 取第1-10行 |
| /hello/ | 取包含“hello”的行 |
| /10:00/,/11:00/ | 取包含“10:00”到包含“11:00”之间的行 |
取列
-F参数:指定列分隔符$n:取第n列,其中$0表示所有列,$NF表示最后一列
举例:
- 取出第5列和第7列:
ls -al . | awk '{print $5,$7}' | column -t - 同时指定行数:
ls -al . | awk 'NR==3||NR==5{print $5,$7}' | column -t - 取出所有的用户名:
grep -vE '^$|^#' /etc/passwd | awk -F : '{print $1}' - 取出所有的用户名和家目录,并用⭐️分隔:
grep -vE '^$|^#' /etc/passwd | awk -F : '{print $1"⭐"$NF}' - 将第1列和最后一列的位置交换输出(分隔符维持原样):
grep -vE '^$|^#' /etc/passwd | awk -F : -v OFS=: '{print $NF,$2,$3,$4,$5,$6,$1}' - 取出指定网卡的ip地址:
ip a s eth0 | awk -F"[ /]+" 'NR==3{print $3}'
⚠️awk后的条件应该使用单引号包裹,因为双引号中的$代表变量,如果使用双引号则需要在取列时加上转译符。此外,awk中的字母都会被识别成变量,如果只是想使用字符串,需要将字母用双引号包裹起来。
awk模式匹配——正则匹配
通过模式匹配可以直接抓取某一列满足特定条件的信息,默认支持拓展正则。
~表示服从后续的正则!~表示不服从后续的正则
举例:找到第3列以1开头的行,输出这行的第1列和第3列
grep -vE '^$|^#' /etc/passwd | awk -F: '$3~/^1/{print $1,$3}'
awk模式匹配——范围模式
/pattern1/,/pattern2/:从满足pattern1的行到满足pattern2的行NR==2,NR==10:从第2行到第10行
awk模式匹配——特殊模式
| 特殊模式 | 应用场景 |
|---|---|
| BEGIN{} | 1)进行简单统计计算,一般不涉及读取文件 2)添加表头 3)用来定义awk变量(很少用,因为可以用-v) |
| END{} | 1)输出统计结果 2)输出数组结果 |
举例:
- 统计空行和注释行的行数:
awk '/^$|^#/{i++}END{print i}' /etc/servicei是变量名,可以随便取 - 求和1-100:
seq 100 | awk '{sum+=$1}END{print sum}'sum是变量名,可以随便取
awk数组
应用场景: 统计每个IP出现的次数、统计每种状态码出现的次数、统计每个AP消耗的流量… 类似于group by。
| shell数组 | awk数组 | |
|---|---|---|
| 形式 | array[0]=hello array[1]=world | array[0]=hello array[1]=world |
| 使用 | echo ${array[0]} ${array[1]} |
print array[0] array[1] |
| 遍历 | for i in ${array[*]} do echo $i done |
for(i in array) print array[i] |
举例:
- 输出hello world:
awk 'BEGIN{a[0]="hello";a[1]="world"; for(i in a) print a[i]}'
1 | |
grep -v '^#' test | awk -F "/|//" '{arr[$2]++}END{for(i in arr) print i,arr[i]}'通过grep去除注释信息sed -n '2,$p' test | awk -F "/+" '{arr[$2]++}END{for (i in arr) print i,arr[i]}'通过sed去除第一行的注释信息- 在以上处理的基础上再追加一个管道排序:
xxx | sort -rnk 2,r代表逆序,n是数字,k指定第2列
条件、循环
语法和java基本一致。
举例:
判断磁盘空间是否充足:df -h | awk -F"[ %]+" 'NR>1{if($5>=70) {print $1,$5,"❌"} else {print $1,$5,"✅"} }'
统计这段话中字符数不小于4的单词:
1 | |
笔记整理自:https://www.bilibili.com/video/BV1244y1e73a
人剑合一
find
1 | |
ack
ack在执行搜索的过程中会自动忽略主流版本控制软件的相关目录,比如 .git 和 .svn。
1 | |
mac的ack支持 --range-start 和 --range-end 两个参数。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!