AI大模型教程
一起来学习

Shell编程之正则表达式

一、正则表达式

1.正则表达式概述

  正则表达式通常用于判断语句中,用来检查某一字符串是否满足某一格式。

  正则表达式是由普通字符元字符组成。普通字符包括小写字母、数字、标点符号及一些其他符号。元字符是指在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。

2.正则表达式的分类

  正则表达式根据从POSIX BRE或者POSIX ERE标准可以分为基本正则表达式扩展正则表达式

基本正则表达式

支持的工具:grepegrepsedawk,注意grep要配合-E或者-P使用。

元字符 含义及用法
转义字符,用于取消特殊符号的含义,例: !n$
^ 匹配字符串开始的位置,例:^a^the^#^[a-z]
$ 匹配字符串结束的位置,例: word$^$匹配空行
. 匹配除n之外的任意的一个字符,例: go.dg..d。如果想要匹配包含n字符可以使用 [.n]
* 匹配前面子表达式0次或者多次,例: goo*dgo.*d
[list] 匹配list列表中的一个字符,例: go[ola]d[abc][a-z][a-z0-9][0-9]匹配任意一位数字
[^list] 匹配任意非list列表中的一个字符,例:[^0-9][^A-Z0-9][^a-z]匹配任意一位非小写字母
{n} 匹配前面的子表达式n次,例: go{2}d[0-9]{2}匹配两位数字
{n,} 匹配前面的子表达式不少于n次,例: gol{2,l}d[0-9]{2,}匹配两位及两位以上数字
{n,m} 匹配前面的子表达式n到m次,例 : go{2,3}d[0-9]{2,3}匹配两位到三位数字
注: egrepawk使用{n}{n,}{n,m}匹配时 {} 前不用加
w 匹配包括下划线的任何单词字符。
W 匹配任何非单词字符。等价于[^A-Za-z0-9_]
d 匹配一个数字字符。
D 匹配一个非数字字符。等价于[^0-9]
s 空白符。
S 非空白符。

扩展正则表达式

支持的工具:egrepawk,注意:使用grep要配合-E或者-P使用,sed要配合-r使用。

元字符 含义及用法
+ 匹配前面子表达式1次以上,例: go+d,将匹配至少一个o,如godgoodgoood
? 匹配前面子表达式0次或者1次,例: go?d,将匹配gdgod
() 将括号中的字符串作为一个整体,例1: g(oo)+d,将匹配oo整体1次以上,如goodgooood
| 以或的方式匹配字符串,例:g(oo|la)d,将匹配good或者 glad

3.正则表达式的使用

  •  * ^ $的用法
[root@localhost opt]# cat testfile6
gd
god
good
goood
gooood
goooabcd
gooooood
gooooooodddd
abccba
abccba123
oooogooood
ooooogd
gold
goad
#查询一串字符中有goo*d字样,且o有0个或多个,此字符串可以不在开头或结尾
[root@localhost opt]# grep "goo*d" testfile6    
god
good
goood
gooood
gooooood
gooooooodddd
oooogooood
#查询以g开头d结尾,中间的o有0个或多个
[root@localhost opt]# grep "^goo*d$" testfile6  
god
good
goood
gooood
gooooood
  • [] [^]的用法
#查询一个字符,其中有一段以go开头d结尾,中间的o、l、a这几种字符中的一种
[root@localhost opt]# grep “go[ola]d” testfile6     
good
gold
goad
#查询一个字符,其中有一段以go开头d结尾,中间的o、l、a这几种字符中的一个或多个
[root@localhost opt]# grep “go[ola]*d” testfile6 
god
good
goood
gooood
gooooood
gooooooodddd
oooogooood
gold
goad
#匹配除了a-g开头的字符
[root@localhost opt]# grep "^[^a-g]" testfile6  
oooogooood
ooooogd
  • {n} {n,} 的用法
#匹配good字符,其中{2}只会匹配前面的o两次
[root@localhost opt]# grep "go{2}d" testfile6 
good
#匹配go..d,其中o至少2次及以上
[root@localhost opt]# grep "go{2,}d" testfile6 
good
goood
gooood
gooooood
gooooooodddd
oooogooood

4.常见例题

电话例题

找出区号025开头的号码,且号码与区号间可以是空格、-、没有,号码必须是5或者8开头的八位数。

02588888888
025-5555555555
025 12345678
025 54321678
025ABC88888
025-85432109
028-85643210
0251-52765421

解题思路

先将电话拆分为3段,第一段找出区号,第二段筛选出号码与区号之间的分隔符,第三段号码后几位。

区号025开头。^是以什么为开头,用()将025作为一个整体

^(025)

号码与区号间可以是空格、-、没有。将题目要求的空格和-写入[],由于?是前面的子表达式0次或1次,0次就符合题目要求的没有

 [ -]?

号码必须是5或者8开头的八位数。用[]确认是5或8数字开头的号码,然后再匹配0-9的7位数结尾的数

[58][0-9]{7}$

总体输出如下

[root@localhost opt]# egrep "^(025)[ -]?[58][0-9]{7}$" iphone.sh 
02588888888
025 54321678
025-85432109
电子邮箱例题

根据 用户名@子域名.[二级域名].顶级域 格式找出符合要求的电子邮箱

zhangsan123@qq.com
li si@163.com
wang@wu@sina.com
zhao liu@126.com
qianqi@sina.com.cn

解题思路

将邮箱拆分为三段,第一段用户名,第二段子域名二级域,第三段顶级域

用户名@:长度要求在6-18位,任意大小写英文,任意数字,除了@符号和空格以外的其它任意符号字符,开头只能是 _ 或者字母

^([a-zA-Z_][^@ ]{5,17})@

子域名.[二级域名]:长度任意,符号只能包含 – _ .

[a-zA-Z0-9_-.]+(.[a-zA-Z0-9_-.]+)?

.顶级域名: 长度在2-5,任意大小写英文

.([a-zA-Z]{2,5})$

总体输出如下

[root@localhost opt]# egrep "^([a-zA-Z_][^@ ]{5,17})@[a-zA-Z0-9_-.]+(.[a-zA-Z0-9_-.]+)?.([a-zA-Z]{2,5})$" mail.sh 
zhangsan123@qq.com
qianqi@sina.com.cn

二、sed编辑器

1.sed编辑器概念

  sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。

  sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储一个命令文本文件中。

2.sed编辑器工作流程

  sed 的工作流程主要包括读取执行显示三个过程:

读取:sed从输入流(文件、管道、标准输入〉中读取一行内容并存储到临时的缓冲区中(又称模式空间,pattern space)。    

执行:默认情况下,所有的sed命令都在模式空间中顺序地执行,除非指定了行的地址,否则临时sed命令将会在所有的行上依次执行。

显示:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空。

 在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。

注意:默认情况下所有的sed命令都是在模式空间内执行的,因此输入的文件并不会发生任何变化,除非是用重定向存储输出。

处理大文件较卡问题

  流编辑器处理大文件比较卡可以使用两种方式来处理。sed命令将大文件分成若干个小文件读取。或者使用cat命令读取全部文件放在临时缓冲区中,然后交给流编辑器(grep、sed、awk)进行处理,由于使用cat命令时IO消耗比较低。

3.sed编辑器用法

命令格式
sed -e '操作' 文件l 文件2 ...
sed -n -e '操作' 文件1 文件2 ...
sed -f 脚本文件 文件1 文件2 ...
sed -i -e '操作' 文件1 文件2 ...
​
sed -e 'n{              #n意为:指定行
操作l
操作2
...
}' 文件1 文件2 ...
常用选项
选项 含义
-e--expression= 表示用指定命令来处理输入的文本文件,只有一个操作命令时可省略,一般在执行多个操作命令使用。
-f--file= 表示用指定的脚本文件来处理输入的文本文件。
-h--help 显示帮助。
-n--quietsilent 禁止sed编辑器输出,但可以与p命令一起使用完成输出。
-i 直接修改目标文本文件。
-r, –regexp-extended 支持正则表达式
常用操作
操作 含义
s 替换,替换指定字符。
d 删除,删除选定的行。
a 增加,在当前行下面增加一行指定内容。
i 插入,在选定行上面插入一行指定内容。
c 替换,将选定行替换为指定内容。
y 字符转换,转换前后的字符长度必须相同。
p 打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容,如果有非打印字符,则以ASCII码输出。其通常与-n选项一起使用。
= 打印行号。
l(小写L) 打印数据流中的文本和不可打印的AscII字符(比如结束符$、制表符t)
常用方式
打印内容
[root@localhost ~]# sed -n -e 'p' testfile1         #打印内容
​
[root@localhost ~]# sed -n -e '=' testfile1         #打印行号
​
[root@localhost ~]# sed -n -e 'l' testfile1         #打印隐藏特殊符号
​
[root@localhost ~]# sed -n -e '=;p' testfile1       #打印行号和内容
[root@localhost ~]# sed -n -e '=' -e 'p'testfile1   #打印行号和内容

sed编辑器的寻址方式

  • 以数字形式表示行区间

  • 用文本模式来过滤出行

[root@localhost ~]# sed -n '1p' testfile1                   #打印第1行
​
[root@localhost ~]# sed -n '$p' testfile1                   #打印最后一行
​
[root@localhost ~]# sed -n '1,3p' testfile1                 #打印1到3行
​
[root@localhost ~]# sed -n '3,$p' testfile1                 #从第3行开始打印,直到最后一行结束
​
[root@localhost ~]# sed -n '1,+3p' testfile1                #打印第1行之后的连续3行,即1-4行
​
[root@localhost ~]# sed '5q' testfile1                      #打印前5行信息后退出,q表示退出
​
[root@localhost ~]# sed -n 'p;n' testfile1                  #打印奇数行,n表示移动到下一行
[root@localhost ~]# sed -n '3{p;n;n;p}' testfile1           #打印第3,5行
​
[root@localhost ~]# sed -n 'n;p' testfile1                  #打印偶数行
[root@localhost ~]# sed -n '2,${n;p}' testfile1             #从第2行开始,从下一行开始打印,即第3、5、7行
​
[root@localhost ~]# sed -n '1,${n;p}' testfile1             #从第1行开始,从下一行开始打印,即第2、4、6行
​
​
[root@localhost ~]# sed -n '/user/p' /etc/passwd            #打印包含user的行
​
[root@localhost ~]# sed -n '/^a/p' /etc/passwd              #打印以a开头的行
​
[root@localhost ~]# sed -n '/bath$/p' t/etc/passwd          #打印以bath结尾的行
​
[root@localhost ~]# sed -n '/ftp|root/p' /etc/passwd       #打印含有ftp或者root的行
[root@localhost ~]# sed -nr '/ftp|root/p' /etc/passwd       #-r表示支持扩展正则表达式
​
[root@localhost ~]# sed -n '2,/nobody/p' /etc/passwd        #打印从第2行开始,直到第一个包含nobody的行结束
​
[root@localhost ~]# sed -n '2,/nobody/=' /etc/passwd        #打印从第2行开始,直到第一个包含nobody的行结束的行号
​
[root@localhost ~]# sed -nr '/ro{1,}t/p' /etc/passwd        #打印包含root的行,root中o的个数可以是1个以上
删除行内容
[root@localhost ~]# sed 'd' testfile1                       #全删
​
[root@localhost ~]# sed '3d' testfile1                      #删除第3行
​
[root@localhost ~]# sed '2,4d' testfile1                    #删除第2到4行
​
[root@localhost ~]# sed '$d' testfile1                      #删除最后一行
​
[root@localhost ~]# sed '/^$/d' testfile1                   #删除空行
​
[root@localhost ~]# sed '/nologin$/d' /etc/passwd           #删除以nologin结尾的文件
​
[root@localhost ~]# sed '/nologin$/!d' /etc/passwd          #"!"表示取反
​
[root@localhost ~]# sed '/2|3/d' testfile2                 #删除第2行和第3行
[root@localhost ~]# sed '/2/,/3/d' testfile2                #从第一个位置打开行删除功能,到第二个位置关闭行删除功能
[root@localhost ~]# sed '/1/,/3/d' testfile2                #从第一个包含1的行打开删除功能,到第一个包含3的行关闭删除功能,然后接着往下扫描重复之前操作,若包含3的行不存在,则一删到底。
替换内容

命令格式

行范围 s/旧字符/新字符串/替换标记

替换标记

数字 表明新字符串将替换第几处匹配的地方
g 表明新字符串将会替换所有匹配的地方
p 打印与替换命令匹配的行,与-n一起使用
w 文件 将替换的结果写到文件中

使用方式

[root@localhost ~]# sed -n 's/root/admin/p' /etc/passwd                 #将匹配行中第一个root替换为admin然后打印替换的行
    
[root@localhost ~]# sed -n 's/root/admin/2p' /etc/passwd                #将匹配行中第二个root替换为admin然后打印替换的行
​
[root@localhost ~]# sed -n 's/root/admin/gp' /etc/passwd                #将匹配行所有root替换为admin然后打印替换的行
[root@localhost ~]# sed -n 's/root/admin/gw file' /etc/passwd           #将匹配行所有root替换为admin然后保存替换的行至file
[root@localhost ~]# sed -n 's/root/admin/gp' /etc/passwd > file         #将匹配行所有root替换为admin然后保存替换的行至file
​
[root@localhost ~]# sed 's/root//g' /etc/passwd                         #将匹配行所有root替换为空的
​
[root@localhost ~]# sed 'l,20 s/^/#/' /etc/passwd                       #在第1到20行进行注释
[root@localhost ~]# sed '/^root/ s/^/#/' /etc/passwd                    #将以root开头的行进行注释
​
[root@localhost ~]# sed '/root/ s/^/#/' /etc/passwd                     #将包含root的行进行注释
[root@localhost ~]# sed -rn 's /.*root.*/#&/p' /etc/passwd              #用正则匹配行内容,然后通过&获取前面匹配的内容进行注释后打印
[root@localhost ~]# sed  -ir 's/.*swap.*/#&/' /etc/fstab                #禁用swap交换空间
[root@localhost ~]# sed -f script.sed testfile2                         #对某个文件执行指定命令文件
​
[root@localhost ~]# sed '1,20w out.txt' /etc/passwd
[root@localhost ~]# sed '1,20 s/^/#/w out.txt' /etc/passwd              #将文件的第1到20行进行注释,然后将修改的行内容保存至指定文件
​
[root@localhost ~]# sed -n 's//bin/bash//bin/csh/p' /etc/passwd     #将文件中/bin/bash替换为/bin/csh,然后打印替换的行
[root@localhost ~]# sed -n 's!/bin/bash!/bin/csh!p' /etc/passwd       #使用"!"作为字符串分隔符,可以使用除了斜杠的其他字符
[root@localhost ~]# sed -i 's994599998939' /etc/passwd             #将94599替换为9893
插入内容

基本使用

[root@localhost ~]# sed '/45/c ABC' testfile2                           #将含有45的行都替换为ABC
​
[root@localhost ~]# sed 'y/145/ABC/' testfile2                          #使所有的1字符转换成a,所有的2字符转换成B,所有的3字符转换成c
​
[root@localhost ~]# sed '1,3a ABC' testfile2                            #在第1行到第3行后都插入ABC新的一行
​
[root@localhost ~]# sed '1i ABC' testfile2                              #在第一行前插入ABC新的一行
​
[root@localhost ~]# sed '5r /etc/resolv.conf' testfile2                 #在第5行读取/etc/resolv.conf文件

保持空间的使用

[root@localhost ~]# sed '/root/{H;d};$G’ /etc/passwd                    #将包含root的行剪切到末尾,H表示复制到剪切板,G表示粘贴到指定行后
​
[root@localhost ~]# sed '1,2H;3,4G' /etc/passwd                     #将1、2行复制到3和4行的下面

高级使用(sed分组概念)

[root@localhost ~]# echo "111222333" | sed -r 's/(111)(222)/21/'      #将字符111和 222互换位置
[root@localhost ~]# echo "111222333" | sed -r 's/^(.)(.*)(.)$/321/'  #将第一个字符和最后一个字符互换

三、awk编辑器

1.概念

  sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个”字段”然后再进行处理。awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。

  在使用awk命令的过程中,可以使用逻辑操作符 &&表示与、||表示或、!表示非;还可以进行简单的数学运算,如+-*/%^分别表示加、减、乘、除、取余和乘方。

2.工作原理

  逐行读取文本,默认以空格或tab键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。

3.用法

命令格式
awk 选项 '模式或条件 {操作}' 文件1 文件2 ...
awk -f 脚本文件 文件l 文件2 ...
常用选项
-F  指定分隔符
awk -F ',' '{print}' file1
常见的内建变量
内建变量 含义
FS 列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与-F作用相同。
NF 当前处理的行的字段个数。$NF代表最后一个字段。
NR 当前处理的行的行号(序数)。
$0 当前处理的行的整行内容。
$n 当前处理行的第n个字段(第n列)。
FILENAME 被处理的文件名。
RS 行分隔符。awk从文件上读取资料时,将根据Rs的定义把资料切割成许多条记录,而awk比较倾向于将一行分成多个一次仅读入一条记录,以进行处理。预设值是n
常用方式
按行输出文本
  • 输出所有内容
[root@localhost opt]# awk '{print}' testfile1 
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
[root@localhost opt]# awk '{print $0}' testfile1 
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
  • 输出指定行内容
###输出第1行内容
[root@localhost opt]# awk 'NR==1 {print}' testfile1 
one
​
###输出第3行内容
[root@localhost opt]# awk 'NR==3 {print}' testfile1 
three
​
###输出第1~3行内容
[root@localhost opt]# awk 'NR==1,NR==3 {print}' testfile1 
one
two
three
[root@localhost opt]# awk '(NR>=1)&&(NR
  • 输出奇偶数行的内容
###输出偶数行的内容
[root@localhost opt]# awk '(NR%2)==0{print}' testfile1 
two
four
six
eight
ten
twelve
​
###输出奇数行的内容
[root@localhost opt]# awk '(NR%2)==1{print}' testfile1 
one
three
five
seven
nine
eleven
  • 输出含有字符串的行
###输出含有root的行
[root@localhost opt]# awk '/root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
​
###输出以root开头的行
[root@localhost opt]# awk '/^root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
​
###输出以nologin结尾的行
[root@localhost opt]# awk '/nologin$/{print}' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
...
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
  • 统计以/bin/bash 结尾的行数
    [root@localhost opt]# awk 'BEGIN {x=0};//bin/bash$/{x++};END {print x}' /etc/passwd
2

此命令等同于grep -c "/bin/bash$" /etc/passwd

BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作;awk再处理指定的文本,之后再执行END模式中指定的动作,END{}语句块中,往往会放入打印结果等语句。

按字段输出文本
  •    输出每行中(以控股或制表位分隔)的第3个字段
[root@localhost opt]# awk -F":" '{print $3}' /etc/passwd
0
1
2
3
4
5
6
...
38
42
29
65534
98
74
70
89
72
1000
  • 输出每行中的第1、3个字段
[root@localhost opt]# awk -F":" '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
...
geoclue 989
ntp 38
gdm 42
rpcuser 29
nfsnobody 65534
gnome-initial-setup 988
sshd 74
avahi 70
postfix 89
tcpdump 72
tang 1000
  • 输出特定条件的行的字段内容
###输出第3个字段的值小于5的第1、3个字段内容
[root@localhost opt]# awk -F":" '$3=1000){print}}' /etc/passwd
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
tang:x:1000:1000:tang:/home/tang:/bin/bash

使用三元运算符输出内容

如果第3个字段的值大于等于第4个字段的值,则把第3个字段的值赋给max,否则第4个字段的值赋给max

[root@localhost opt]# awk -F":" '{max=($3>=$4)?$3:$4;{print max}}' /etc/passwd
0
1
2
4
7
5
6
7
12
11
100
50
99
192
81
999
998
997
32
996
995
994
173
993
172
171
75
992
991
107
59
990
113
989
38
42
29
65534
988
74
70
89
72
1000

输出两种指定条件的内容

###输出以冒号分隔且第7个字段中包含/bash的行的全部内容
[root@localhost opt]# awk -F":" '$7~"/bash"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
tang:x:1000:1000:tang:/home/tang:/bin/bash
​
###输出以冒号分隔且第7个字段中包含/bash的行的第1个字段
[root@localhost opt]# awk -F":" '$7~"/bash"{print $1}' /etc/passwd
root
tang
​
###输出第1个字段中包含root且有7个字段的行的第1、2个字段
[root@localhost opt]# awk -F":" '($1~"root")&&(NF==7){print $1,$2}' /etc/passwd
root x
​
###输出第7个字段既不为/bin/bash,也不为/sbin/nologin的所有行
[root@localhost opt]# awk -F":" '($7!="/bin/bash")&&($7!="/sbin/nologin"){print}' /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
通过管道、双引号调用 Shell命令

   统计以冒号分隔的文本段落数,END{}语句块中,往往会放入打印结果等语句。

  每处理完一条记录,NR值加1

[root@localhost opt]# echo $PATH | awk 'BEGIN {RS=":"}; END{print NR}'
5
  • 调用wc -l命令统计使用bash 的用户个数
[root@localhost opt]# awk -F: '/bash$/{print | "wc -l"}' /etc/passwd
2
[root@localhost opt]# awk -F: '/bash$/{print}' /etc/passwd | wc -l
2
此命令等同于grep -c "bash$" /etc/passwd
  • 查看当前内存使用百分比
[root@localhost opt]# free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}'
33%
[root@localhost opt]# free -m | awk '/Mem:/ {print $3/$2 * 100"%"}'
24.1379%
  • 查看当前CPU空闲率
[root@localhost opt]# top -b -n 1 | awk -F"," '/%Cpu/ {print $4}' | awk '{print $1}'
100.0
[root@localhost opt]# top -b -n 1 | grep Cpu | awk -F ',' '{print $4}' | awk '{print $1}'
100.0
-b -n 1表示只需要1次的输出结果。
  • 查看当前磁盘的情况
###查看当前磁盘的使用率
[root@localhost opt]# df | awk '$NF=="/" {print $5}'
13%
###查看当前磁盘的空闲率
[root@localhost opt]# df | awk '$NF=="/" {print $5}' | awk -F% '{print 100-$1"%"}'
87%
  • 显示上次系统重启时间
[root@localhost opt]# date -d "$(awk -F "." '{print $1}' /proc/uptime) second ago" +"%F %H:%M:%S"
2023-05-15 08:44:02
[root@localhost opt]# date -d "$(cat /proc/uptime | awk -F. '{print $1} ' ) second ago" +"%Y-%m-%d %H:%M:%S"
2023-05-15 08:44:02
  • 常见日期用法
###当月第一天
[root@localhost opt]# date +%Y%m01
20230501
​
##下个月第一天
[root@localhost opt]# date -d "1 month" +%Y%m01
20230601
​
###上个月第一天
[root@localhost opt]# date -d "-1 month" +%Y%m01
20230401
[root@localhost opt]# date -d "1 month ago" +%Y%m01
20230401
​
###明天
[root@localhost opt]# date -d "1 day" +%Y%m%d
20230516
​
##昨天
[root@localhost opt]# date -d "-1 day" +%Y%m%d
20230514
[root@localhost opt]# date -d "yesterday" +"%Y%m%d" 
20230514
​
###上个月最后一天
[root@localhost opt]# date -d "$(date +%Y%m01) -1 day" +%Y%m%d
20230430
​
###当月最后一天
[root@localhost opt]# date -d "$(date -d "1 month" +%Y%m01) -1 day" +%Y%m%d
20230531
  • 每个月最后一天去执行指定文件
方式1:脚本中进行判断
###当月最后一天
lastday=$(date -d "$(date -d "1 month" + "%Y%m01") -1 day" +"%Y%m%d")
###今天
today=$(date +%Y%m%d)
###判断今天是否是最后一天
if [ "$today" == "$lastday" ];then 执行文件
​
方式2:计划性任务中判断
0 0 28-31 if [ "$(date -d "$(date -d "1 month" + "%Y%m01") -1 day" +"%Y%m%d")" == "today=$(date +%Y%m%d)"];then 执行文件
  • 调用w命令,并用来统计在线用户数
[root@localhost opt]# awk 'BEGIN{n=0;while("w" | getline) n++ ;{print n-2}}'
2
  • 调用hostname,并输出当前的主机名
[root@localhost opt]# awk 'BEGIN{"hostname" | getline ;{print $0}}'
localhost.localdomain
  • 获取奇偶数行
###获取偶数行
[root@localhost opt]# seq 10 | awk '{getline;print $0}'
2
4
6
8
10
​
###获取奇数行
[root@localhost opt]# seq 10 | awk '{print $0;getline}'
1
3
5
7
9

   当getline左右无重定向符|时,awk首先读取到了第一行,就是1,然后使用getline就得到了1下面的第二行,就是2,因为getline之后,awk会改变对应的NFNRFNR$0等内部变量,所以此时的$0的值就不再是1,而是2了,然后将它打印出来。

   当getline左右有重定向符|时,getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。

  • 查看使用特定分隔符的字符串
###输出A B C D字符串
[root@localhost opt]# echo "A B C D"
A B C D
​
###输出ABCD字符串以及用|分隔的字符串
[root@localhost opt]# echo "A B C D" | awk '{OFS="|";print $0;$1=$1;print $0}'
A B C D
A|B|C|D
​
###输出以逗号分隔的ABCD字符串
[root@localhost opt]# echo "A B C D" | awk 'BEGIN{OFS=","};{$2=$2;print $0}'
A,B,C,D
echo "A B C D" | awk '{print $1","$2","$3","$4}'
A,B,C,D

OFS是列输出分隔符,可以用来指定分隔符。

$1=$1是用来激活$0的重新赋值,也就是说字段$1…和字段数NF的改变会促使awk重新计算$0的值,通常是在改变OFS后而需要输出$0时这样做。

按数组输出文本以及统计
  • 下标是数字时输出文本
[root@localhost opt]# awk 'BEGIN{a[0]=10;a[1]=20;print a[1]}'
20
[root@localhost opt]# awk 'BEGIN{a[0]=10;a[1]=20;print a[0]}'
10
  • 下标是一串字符时输出文本
[root@localhost opt]# awk 'BEGIN{a["abc"]=10;a["xyz"]=20;print a["abc"]}'
10
[root@localhost opt]# awk 'BEGIN{a["abc"]=10;a["xyz"]=20;print a["xyz"]}'
20

其中字符串需要用双引号包起来。

  • 下标是数字,使用循环输出文本
[root@localhost opt]# awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a){print a[1]}}'
20
20
20
[root@localhost opt]# awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a){print a[2]}}'
30
30
30

其中BEGIN中的命令只执行一次

  • 通过数组统计重复行的数量
[root@localhost opt]# cat test.txt
aaa
aaa
bbb
ccc
aaa
bbb
aaa
###统计重复字符串的数量以及输出对应的字符串
[root@localhost opt]# awk '{a[$1]++}END{for(i in a){print a[i],i}}' test.txt 
4 aaa
1 ccc
2 bbb
###从大到小排序
[root@localhost opt]# awk '{a[$1]++}END{for(i in a){print a[i],i}}' test.txt |sort -r
4 aaa
2 bbb
1 ccc

a[1]初始为0,a[1]++后即为1,而这里awk中的a[1]++最终的值是由test.txt文本内容有多少行决定的,文本逐行读取完毕后再执行END中的命令。

  • 统计登录失败的ip地址出现的次数
[root@localhost log]# cat /var/log/secure | awk '/Failed password/{print $11}' | sort -n |uniq -c
      3 192.168.145.30
      1 192.168.145.45
​
[root@localhost log]# cat /var/log/secure | awk '/Failed password/{a[$11]++}; END{for(i in a){print a[i],i}}'
1 192.168.145.45
3 192.168.145.30
  • 计算物理内置使用百分比和剩余内存百分比
1、cat /proc/meminfo  | awk '/MemTotal|MemFree|MemAvailable/ {count++; val[count]=$2} END {print val[2]/val[1]*100"%"; print val[3]/val[1]*100"%"}'

2、cat /proc/meminfo  | awk '/MemTotal|MemFree|MemAvailable/ {val[NR-1]=$2} END {print val[1]/val[0]*100"%"; print val[2]/val[0]*100"%"}' 

3、cat /proc/meminfo  | awk '/MemTotal|MemFree|MemAvailable/ {val[i++]=$2} END {print val[1]/val[0]*100"%"; print val[2]/val[0]*100"%"}' 

文章来源于互联网:Shell编程之正则表达式

相关推荐: 【亲测免费】 探索智能对话:基于Qt5的文心一言API调用应用

探索智能对话:基于Qt5的文心一言API调用应用 【下载地址】使用Qt5调用文心一言API的应用程序 本项目旨在使用Qt5框架开发一个应用程序,通过调用文心一言的API实现以下功能:1. **网络请求模块**:使用Qt5中的网络请求模块实现对文心一言API的访…

赞(0)
未经允许不得转载:5bei.cn大模型教程网 » Shell编程之正则表达式
分享到: 更多 (0)

AI大模型,我们的未来

小欢软考联系我们