正则表达式
符号
1、通配符: * [ ] { } $—开头 ^—结尾 . —匹配\n之外的任意一个字符
2、转义符: /r / n \
\转义符将包含特殊含义的符号,定义为原意
3、元字符:表示特殊含义的字符/符号
4、连字符: && -a || -o ; ,
表示次数
egrep或-E可以不使用转义
* #匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.* #任意长度的任意字符,不包括0次,也就是匹配所有
\? #匹配其前面的字符出现0次或1次,即:可有可无
\+ #匹配其前面的字符出现最少1次,即:肯定有且 >=1 次
\{n\} #匹配前面的字符=n次
\{m,n\} #匹配前面的字符至少m次,至多n次
\{,n\} #匹配前面的字符至多n次,<=n
\{n,\} #匹配前面的字符至少n次
位置锚定
^ #行首锚定, 用于模式的最左侧
$ #行尾锚定,用于模式的最右侧
^root$ #用于模式匹配整行 (单独一行 只有root)
^$ #空行
^[[:space:]]*$ #空白行
\< 或 \b #词首锚定,用于单词模式的左侧(连续的数字,字母,下划线都算单词内部)
\> 或 \b #词尾锚定,用于单词模式的右侧
\<root\> #匹配整个单词
分组或其他
分组:()
或者:\|
三剑客
grep—按关键字找
grep [选项]… 查找条件 目标文件
选项:
-m # 匹配#次后停止
grep -m 1 root /etc/passwd #多个匹配只取第一个
-v 显示不被pattern匹配到的行,即取反
grep -Ev '^[[:space:]]*#|^$' /etc/fstab
-i 忽略字符大小写 #可有可无
-n 显示匹配的行号
-c 统计匹配的行数 (参与记录 词频)
grep -c root /etc/passwd #统计匹配到的行数
-o 仅显示匹配到的字符串
-q 静默模式,不输出任何信息
-A # after, 后#行
grep -A3 root /etc/passwd #匹配到的行的后3行也显示出来
-B # before, 前#行
-C # context, 前后各#行
-e 实现多个选项间的逻辑or关系,如:grep –e ‘cat ' -e ‘dog' file
grep -e root -e bash /etc/passwd #包含root或者包含bash 的行
-w 匹配整个单词
grep -w root /etc/passwd
-E 使用ERE,相当于egrep,使用扩展正则
-F 不支持正则表达式
-f file 根据模式文件,处理两个文件相同内容 把第一个文件作为匹配条件
-r 递归目录,但不处理软链接
-R 递归目录,但处理软链接
附
sort—排序
以行为单位对文件内容进行排序,也可以根据不同的数据类型来排序
语法格式:
sort 选项 文件
cat file | sort 选项
常用选项:
-f:忽略大小写,默认会大写字母排在前面
-b:忽略每行前面的空格
-n:按照数字进行排序
-r:反向排序
-u:等同uniq,表示相同的数据仅显示一行,去重
-t:指定字段分隔符,默认使用tab键分隔
-k:指定排序字段
-o <输出文件>:将排序后的结果转存至指定文件
sort -n test.txt ---按数字大小进行排序
sort -n -r test.txt ---倒序排列
sort -u test.txt ---重复的数据只展示一次,相当于去重
cat /etc/passwd | sort -o ky27.txt ---把整个passwd的文件,传给kgc.txt
cat -n /etc/passwd | sort -n -o ky27.txt #按照源文件的顺序传
uniq—快捷去重
uniq命令用于报告或者忽略文件中连续的重复行,常与sort命令结合使用。
格式:
uniq [选项] 参数
cat 文件| uniq 选项
-c 统计连续重复的行的次数,并且合并重复的行
-u 显示仅出现一次的行(包括不连续的重复行)
-d 仅显示重复出现的行(必须是连续的重复行)
uniq -u test.txt ---只显示出现一次的行
uniq -d test.txt ---只显示连续重复的行
sort -n test.txt | uniq -c ---对重复的数据行计数,并且去重输出
sort -n test.txt | uniq -u ---只展示不重复的数据行
sort -n test.txt | uniq -d ---只展示重复的数据行
tr—替换、压缩和删除
语法格式:
tr 选项 参数
常用选项:
-c:保留字符集1的字符,其他的字符(包括换行符\n)用字符集2替换
-d:删除所有属于字符集1的字符
-s:将重复出现的字符串压缩为一个字符串,用字符集2 替换 字符集1
-t:字符集2 替换 字符集1,不加也行
参数:
字符集1:
指定要转换或删除的原字符集。当执行转换操作时,
必须使用参数”字符集2“指定转换操作时,必须使用参数”字符集2“指定转换的目标字符集。
但执行删除操作时,不需要参数”字符集2“
字符集2:
指定要转换成的目标字符集
echo 192.168.233.22 | tr '.' ' ' ---把"." ,替换成空格
echo ABC | tr "A-Z" "a-z" ---大写替换成小写
echo abc | tr -c 'ab' 'a' ---保留了ab,替换了c,输出aa
echo abc | tr -d 'ab' ---删除ab,打印c
sort -n test.txt | tr -s '\n' ----排序输出,压缩空行为一个
echo $PATH | tr -s ":" "\n" ---把":"替换为换行
cut—快速裁剪命令
expr substr 截取方法
[root@localhost tr]#i=12345678
[root@localhost tr]#expr substr $i 1 3
123
[root@localhost tr]#expr substr $i 2 5
23456
cut截取方法
对字段进行截取和剪裁
格式:
格式一:cut [选项] 参数
格式二:cat file | cut [选项]
-d 指定分隔符(默认分隔符为Tab)
-f 按字段进行截取。指定第n个字段;
-b 以字节为单位进行截取
-c 以字符为单位进行截取
–complement 排除所指定的字段
–output-delimiter 更改输出内容的分隔符
[root@localhost tr]# cut -d ':' -f 1-3 /etc/passwd #已":"作为分隔符,指定第一个到第三个字段进行输出
[root@localhost ~]# head -n 2 /etc/passwd|cut -d ':' --complement -f 2 #指定已":"作为分隔符,但是删除了第二个字段进行输出
[root@localhost ~]# head -n 2 /etc/passwd|cut -d ':' -f 1-5 --output-delimiter='@' #将分隔符转换为@,进行输出
split—文件拆分
split命令用于在Linux下将大文件拆分为若干小文件。
格式:split 选项 参数 原始文件 拆分后文件名前缀
-l 指定行数
-b 指定文件的大小
[root@localhost opt]# cp /etc/passwd /opt/test2.txt
[root@localhost tr]# split -l 20 test2.txt sc
[root@localhost opt]# split -b 2m httpd-2.4.29.tar.bz2 sc 指定文件大小,不需要大小写
paste—文件合并
按照字段来进行文件的合并
格式:
paste [选项] 文件1 文件2
-d 用于指定文件的分隔符(默认情况下为制表符"\n")
-s 将列和行的内容进行互相交换
paste a b和cat a b 之间的区别 (左右合并)
###面试题 统计当前主机的连接状态
[root@localhost ~]# ss -nta | grep -v '^State' |cut -d " " -f 1| sort | uniq -c
3 ESTAB #表示建立的 TCP 连接处于活动状态
17 LISTEN
#####统计当前连接主机数
[root@localhost opt]# ss -nt | tr -s " "|cut -d " " -f 5 | sort -n | uniq -c
1 Local
2 192.168.233.21:22
eval—变量扫描器
命令字前加上eval,shell会在执行命令之前扫描它两次,
eval命令首先会先扫描命令行进行所有的置换,然后再执行命令,
该命令适用于那些一次扫描无法实现功能的变量,该命令会对变量进行两次扫描。
脚本运用测试:
#!/bin/bash
#这是一个验证eval扫描的脚本
a=100
b=a
echo "普通echo输出的变量b的值为:" \$$b
eval echo "经过eval扫描输出变量b的值为:" \$$b
sed—按行找
sed 即 Stream EDitor,和 vim 不同,sed是行编辑器
工作过程
sed的工作流程主要包括读取、执行和显示三个过程:
-
读取: sed从输入流 (文件、管道、标准输入) 中读取一行内容并
存储到临时的缓冲区中(又称模式空间,pattern space )。 -
执行: 默认情况下,所有的sed命令都在模式空间中顺序地执行,除非指定了行的地址,
否则sed命令将会在所有的行上依次执行。 -
显示: 发送修改后的内容到输出流。在发送数据后,
模式空间将会被清空。在所有的文件内容都被处理完成之前,上述过程将重复执行,
直至所有内容被处理完。
在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。
注意:默认情况下所有的sed命令都是在模式空间内执行的,
因此输入的文件并不会发生任何变化,除非使用"sed -i"修改源文件、或使用重定向输出到新的文件中。
基本操作格式:
sed -e '操作' 文件1 文件2
sed -e '操作' 文件1 文件2
sed -f 脚本文件 文件1 文件2
sed -i -e '操作' 文件1 文件2
执行多条命令的格式:
方式一:
sed -e '操作1' -e '操作2' 文件
sed -n -e '/^r/p' -e '/^b/p' /etc/passwd
方式二:
sed -e '操作1;操作2' 文件
常用选项
-e 或--expression=:
表示用指定命令来处理输入的文本文件,只有一个操作命令时可省略,一般在执行多个操作命令使用
-f 或--file=:表示用指定的脚本文件来处理输入的文本文件。
-h 或--help:显示帮助。
-i 直接修改目标文本文件 慎用
-n 仅显示script处理后的结果
操作符
s:替换,替换指定字符。
d:删除,删除选定的行。
a:增加,在当前行下面插入一行指定内容。
i:插入,在选定行上面插入一行指定内容。
c:替换,将选定行替换为指定内容。
y:字符转换,转换前后的字符长度必须相同。
p:打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,
则以 ASCII 码输出。其通常与“-n”选项一起使用。
=:打印行号。
n;p 打印偶数的行
p;n 打印奇数的行
l(小写L):打印数据流中的文本和不可打印的ASCII字符(比如结束符$、制表符\t)
r:扩展正则表达式
经典技术题
怎么解决sed命令处理容量过大,或则内容过多的而导致执行效率慢的问题?
解决方案一(推荐用法):
使用split命令进行文件分割(例如文件如果是百万行,就创建一个单独的目录将文件分割为一百个为一万行的文本)
再使用sed命令进行处理,除了split分割,也可以使用一个遍历分割shell脚本进行执行
split -l -30 test1.txt se --按行分割 #用行开分割更直观,推荐工作中使用
split -b 400M test1.txt se --按大小分割
解决方案二:
使用cat 文件名|sed 处理
(但是该方案只能针对中大型的文件文本,如果文本量过大,处理效果不好)
增删改查
打印
sed ''
sed '' /etc/fstab #查看文件内容
sed '' < /etc/fstab #可以支持重定向输入
cat /etc/passwd |sed '' #也可以支持管道符
默认打印方式
sed -e 'p' test1.txt #sed有一个默认输出,加上P,会打印两行
sed -n 'p' test1.txt #n禁止了默认输出,就只有一行sed -n 2p #打印第二行
打印时对行号的操作
sed -n '=' test1.txt ---只显示行号
sed -n '=;p' test1.txt ---显示行号和每行的内容
寻址打印
方式一:按照行号寻求内容
sed -n '1p' test1.txt #打印第一行
sed -n '4p' test1.txt #打印第四行
sed -n '$p' test1.txt #打印最后一行
方式二:进行行号范围区间的打印
sed -n '1,3p' test1.txt #打印1-3行
sed -n '5,$p' test1.txt #打印第五行到最后一行
sed -n '2,+2p' test1.txt #打印第二行+两行的内容,相当于2,4p
sed -n '3p;5p' test1.txt #输出第三行和第五行
方式三:指定间隔打印
sed -n -e '2p' -e'$p' test1.txt #打印第二行和最后一行
sed -n -e '2p' -e'3p' test1.txt #打印第二行和第三行
方式四:对奇数行和偶数行的打印
sed -n 'n;p' test1.txt #打印偶数的行
sed -n 'p;n' test1.txt #打印奇数的行
sed -n '3,${p;n}' 2.txt #打印第三行开始的奇数行
n在p前面,跳过一行,打印下一行,就是偶数行;
在后面,就是打印第一行,然后跳过一行,形成奇数行
文本模式过滤行内容
方式一:对包含的字符串进行过滤打印
sed -n '/o/p' test1.txt #包含o的所有行
sed -n '/th/p' test1.txt #包含th的所有行
方式二:应用基础正则表达式进行打印
sed -n '/^root/p' /etc/passwd #以root为开头的所有内容,全文本搜索
sed -n '/bash$/p' /etc/passwd #以bash结尾的所有内容,全文本搜索
sed -n '4,/bash$/p' /etc/passwd #从第四行开始,一直打印到第一个以bash为结尾的所在行
方式三:使用扩展正则表达式进行打印
注意:
sed -r 支持扩展正则表达式。同时在 使用{n}、{n,}、{n,m}时,括号{}前不需要加反斜杠\ 。
sed -r -n '/(99:){2,}/p' /etc/passwd #包含有两个99:的内容所在行
sed -r -n '/^root|bash$/p' /etc/passwd #包换以root开头,或者以bsah结尾的内容所在行
删除
sed -i 时会对文本进行实际操作(建议对目标文件先进行备份,再进行操作)
通过行号进行删除
sed 'd' test1.txt #删除所有,什么也不打印
sed -n '3d;p' test1.txt #删除第三行,打印剩余的所有内容
sed -n '5,8d;p' test1.txt #删除5到8行,打印剩余的所有内容
sed -n '5,$d;p' test1.txt #删除5到最后一行行,打印剩余的所有内容
sed '4,6!d' test1.txt #除了4-6行,其他的全部删除
如果要生效:sed -i -n (会删除源文件)
匹配字符串内容删除
sed '/one/d' test1.txt #删除包含one的行
sed '/one/,/six/d' test1.txt #删除one-six的行
sed '/one/,/six/!d' test1.txt #除了one-six的行,其余的全部删除,反向删除
sed '/six/!d' test1.txt #除了six的行,其余的全部删除,反向删除
字符串搭配正则进行删除
删除空行的三种方法
grep -v "^$" test1.txt #过滤出非空行
cat test1.txt |tr -s "\n" #压缩换行符
sed '/^$/d' test1.txt #删除空行
替换
格式:
行范围 s/旧字符串/新字符串/替换标记
替换标记
数字:表明新字符串将替换第几处匹配的地方
g:表面新字符串将会替换所有匹配的地方
p:打印与替换命令匹配的行,与-n一起使用
w文件:将替换的结果写入文件中
sed命令的替换中
s:替换字符串
c:整行替换
y:字符替换,替换前后的字符串长度必须相同
sed -n 's/root/test/2p' /etc/passwd #指定有root这几行的第二个root,替换为了test
sed -n 's/root/test/gp' /etc/passwd #所有的root都替换为test
sed -n '/^root/ s/^/#/p' /etc/passwd #以root开头开始处理,把开头为空的替换为#,注释掉
字母字符进行大小写的替换
sed 's/[A-Z]/\l&/g' test1.txt ---将大写全部转换为小写,
l&是转换小写的一种特殊的符号,前面要加转义符“\”
sed 's/[a-z]/\u&/' test1.txt ---把首字母替换成大写,
u&是转换首字母大写的一种特殊的符号,前面要加转义符“\”
sed 's/[a-z]/\U&/g' test1.txt ---末尾加上了一个g,全部转换成大写
整行替换
sed '/ONE/c 22' test1.txt
sed '/TWO/c TEST' test1.txt
单字符的替换
使用y,是对单个字符进行替换,每个字符需要一一对应,不是整体替换。前后字符串长度需要一致,不然会报错
只要有匹配的单字符会全部替换
sed 'y/TH/12/' test1.txt
增加
a:在下一行添加内容
i:在上一行插入内容
r:在行后读入文件内容
sed '/three/a 123' test1.txt #行后
sed '/three/i 123' test1.txt #上一行
sed '/three/r test.sh' 123.txt #当前行的下一行
sed '$r test2.txt' test1.txt ---先读取test1内容,然后再test2的末行插入test2的所有内容
sed '$a 123' 123.txt #在123.txt的文件最后一行插入123
sed '$i 123' 123.txt #在123.txt的文件最后后面的行中插入123
sed命令中字符串和字符的位置交换
echo ky103yht | sed -r 's/(ky103)(yht)/\2\1/'
-----yhtky103
echo ky103yhtdxl | sed -r 's/(ky103)(yht)(dxl)/\3\2\1/'
-----dxlyhtky103
echo ky103yhtdxl | sed -r 's/(ky103)(yht)(dxl)/\2\1/'
-----yhtky103
echo ky103yhtdxl | sed -r 's/(ky103)(yht)(dxl)/\3\1/'
-----dxlky103
echo ky103yhtdxl | sed -r 's/(ky103)(yht)(dxl)/\3\2/'
-----dxlyht
echo 张涛涛真的帅 | sed -r 's/(.)(.)(.)(.)(.)(.)/\6\5\4\3\2\1/' #前面的点表示字符位置,后面的数字表示对应的交换顺序
帅的真涛涛张
sed -f 指定命令来对第二个文件的行进行处理。
cat 123.txt
-----/IPADDR=192.168.233.21/c IPADDR=10.10.10.10
cat 456.txt
-----IPADDR=192.168.233.21
sed -f 123.txt 456.txt
-----IPADDR=10.10.10.10
cat ky27.txt
-----s/ /_/g
cat ky27sed.txt
-----hello world
-----yht dxl
sed -f ky27.txt ky27sed.txt
-----hello_world
-----yht_dxl
面试题:提取版本号
[root@localhost opt]# grep -E "[0-9]+\." 1.txt
ant-1.9.7.jar
ant-launcher-1.9.7.jar
antlr-2.7.7.jar
antlr-runtime-3.4.jar
aopalliance-1.0.jar
archaius-core-0.7.6.jar
asm-5.0.4.jar
aspectjweaver-1.9.5.jar
bcpkix-jdk15on-1.64.jar
bcprov-jdk15-1.46.jar
bcprov-jdk15on-1.64.jar
checker-compat-qual-2.5.5.jar
[root@localhost opt]# cat 1.txt |sed -r 's/(.*)-(.*)(\.jar)/\1\2\3/' #完整版
[root@localhost opt]# cat 1.txt |sed -r 's/.*-(.*)(\.jar)/\1\2/' #把-前面的取消了
[root@localhost opt]# cat 1.txt |sed -r 's/.*-(.*)\.jar/\1/' #把.jar是不在引用,正确结果
#-r 表示引用扩展正则,(.*)表式"-"前面的所有,"-",就是"-",第二个(.*)表示"-"后面的内容到.jar,(\.jar)的第三个部分
1.9.7
1.9.7
2.7.7
3.4
1.0
0.7.6
5.0.4
1.9.5
1.64
1.46
1.64
2.5.5
查看指定时间内的日志:
[root@localhost ~]#sed -n '/2023:08:09/,/2023:09:42:37/p' /var/log/messages #没有内容
[root@localhost network-scripts]# sed -n '/Mar 23 21:00:01/,/Mar 23 21:30:01/p' /var/log/messages #开头的格式要一致
Mar 23 21:00:01 localhost systemd: Started Session 70 of user root.
修改网卡的IP地址
[root@localhost network-scripts]# sed -i '/IPADDR=192.168.233.21/c IPADDR=10.10.10.10' ifcfg-ens33
[root@localhost network-scripts]# cat ifcfg-ens33
TYPE=Ethernet
DEVICE=ens33
ONBOOT=yes
BOOTPROTO=static
IPADDR=10.10.10.10
NETMASK=255.255.255.0
GATEWAY=192.168.233.2
DNS1=192.168.233.2
[root@localhost network-scripts]# sed -i 'y/10.10.10.10/192.168.233.21/' ifcfg-ens33 #用单个字符串替换会报错
sed:-e 表达式 #1,字符 29:“y”命令的字符串长度不同
总结
-
sed命令是一种流编辑器读取文件会进行逐行读取加上指令操作,所以过大的文件一定要拆分后再交给sed处理
-
sed -r 搭配扩展正则表达式使用,使用{n} {n,} {n,m} 不需要加“\”
-
用 -i 时一定要先备份(尤其对重要文件的操作),或者时先实验好确定无误时,再使用 -i
-
sed 命令 的重点在于增删改查四个功能,可以运用在脚本中对重要文件配置的修改,添加等作用尤其有效
awk—按列找
默认以空格或tab键作为分隔符作为分隔,并按模式或者条件执行编辑命令。
以空格做为分隔符,多个空格他会自动压缩成一个
AWK信息的读入也是逐行指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理.
1、按照命令找指定的行
2、找到的行打印,操作 awk默认的操作就是打印
可以在无交互 的情况下实现相当复杂的文本操作,被广泛应用于 Shell 脚本,完成各种自动化配置任务。
awk [-F] ’ ’ 文件名
分隔符 操作符 怎么干 处理对象
工作过程
第一步:执行BEGIN{action;… }语句块中的语句。
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,
从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,
比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,
比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
pattern语句块中的通用命令是最重要的部分,也是可选的。
如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块
工作原理:
sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个“字段”然后再进行处理,
且默认情况下字段的分隔符为空格或 tab 键。
awk 执行结果可以通过 print 的功能将字段数据打印显示
awk的基本格式及其内置变量:
awk 选项 ‘模式或条件 {操作}’ 文件1 文件2…
-F “分隔符” 指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符
-v(小v) var=value 变量赋值
注意一定是单引号:‘模式或条件 {操作}’
{ }外指定条件,{ }内指定操作。
用逗号指定连续的行,用 || 指定不连续的行。&&表示”且“。
awk {print $1,$2,$3}
内置变量,不能用双引号括起来,不然系统会把它当成字符串。
内置变量
$0: 当前处理的行的整行内容 打印所有
n
:
当前处理行的第
n
个字段(第
n
列)
N
R
:
当前处理的行的行号(序数)
N
F
:
当前处理的行的字段个数。
n: 当前处理行的第n个字段(第n列) NR: 当前处理的行的行号(序数) NF: 当前处理的行的字段个数。
n:当前处理行的第n个字段(第n列)NR:当前处理的行的行号(序数)NF:当前处理的行的字段个数。NF代表最后一个字段
FS: 列分割符。指定每行文本的字段分隔符,输入内容的分隔符,
默认为空格或制表位。与"-F"作用相同 用-F可以不加单引号 -F:,用FS必须用=“”
OFS:输出内容的列分隔符
FILENAME:被处理的文件名
RS: 行分隔符。awk从文件中读取资料时,
将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录进行处理。预设值是"\n"
基本打印用法:
[root@localhost ~]# awk ‘’
#什么都不写 空没有效果
[root@localhost kyio]# awk ‘{print}’
11
11
22
22
[root@localhost opt]# awk ‘0{print}’ test1.txt
[root@localhost opt]# awk ‘1{print}’ test1.txt
two one one
twotwo
three three
four
0和1放置{ }前,能够起到限制打印内容的作用(默认为"1"),如果为0,就不打印内容
awk ‘{print $0}’ test1.txt ----$0,代表整行内容;awk是逐行读取处理,配合$0,就是打印所有内容
$1只取第一列,可以对行切片,输出列
[root@localhost opt]#awk ‘{print NR}’ test1.txt ----打印行号,告诉我们有几行;
[root@localhost opt]#awk ‘{print NR,$0}’ test1.txt ----不仅打印行号,还把每行对应的内用一起展示,
比sed展示的内容更直观
[root@localhost opt]#awk ‘NR3{print}’ test1.txt ----指定打印出第三行的内容
[root@localhost opt]#awk 'NR3,NR5{print}’ test1.txt ----打印3-5行的内容
[root@localhost opt]#awk 'NR3;NR==5{print}’ test1.txt ----打印第三行和第五行
[root@localhost opt]awk ‘(NR>=3)&&(NR<=5){print}’ test1.txt -----正则的表达方式,打印3-5行的内容
奇偶行打印:
[root@localhost opt]awk ‘NR%20{print}’ test1.txt #打印偶数行
[root@localhost opt]awk 'NR%21{print}’ test1.txt #打印奇数行
awk运算:
[root@localhost home]# awk ‘BEGIN{print 100+200}’
300
[root@localhost home]# awk ‘BEGIN{print 10.2+20.3}’
30.5
[root@localhost home]# awk ‘BEGIN{print 10.2*20.3}’
207.06
[root@localhost home]# awk ‘BEGIN{print 10.2/20.3}’
0.502463
[root@localhost home]# awk ‘BEGIN{print 10.2-20.3}’
-10.1
[root@localhost ~]# awk 'BEGIN{print 32}’ #^和都是幂运算
9
[root@localhost ~]# awk ‘BEGIN{print 2^3}’
8
附加:getline
工作过程
1、当getline左右无重定向符号(“<”,“>”)或者管道符号(“|”)时,
awk首先读取的是第一行,而getline获取的是光标跳转至下一行的内容(也就是第二行)。
2、当getline左右有管道符号或重定向符时,
getline则作用定向输入文件,由于文件是刚打开,并没有被awk读入一行,
而只是getline读入,所以getline返回的是文件的第一行,而不是跳转至一行输入
原因:getline运行之后awk会改变NF,NR,$0,FNR等内部变量,所以此时读取$0的行号不再为1,而是2
awk ‘{getline;print $0}’ test1.txt #相当于打印了偶数行
awk ‘{print $0;getline}’ test1.txt #相当于打印了奇数行
[root@localhost opt]# awk ‘{getline < “test1.txt”; print $0 > “test2.txt”;}’ test1.txt
#使用重定向把test1输出给test2
[root@localhost opt]# ls | awk ‘{getline line; print $0, line;}’
test1.txt test2.txt
#把ls的输出传递给getline函数,
line是变量 把ls的内容输出给变量,然后打印出结果,如果无内容,不做任何操作
文本内容匹配过滤打印:
awk ‘/^root/{print}’ /etc/passwd
awk ‘/bash$/{print}’ /etc/passwd
BEGIN打印模式:
格式:awk ‘BEGIN{…};{…};END{…}’ 文件
处理过程:
1、在awk处理指定的文本之前,需要先执行BEGIN{…}模式里的命令操作
2、中间的{…} 是真正用于处理文件的命令操作
3、在awk处理完文件后才会执行END{…}模式里的命令操作。END{ }语句块中,往往会放入打印结果等语句。
[root@localhost opt]# awk ‘BEGIN{x=1};{x++};END{print x}’ test1.txt
10
对字段进行处理打印:
[root@localhost opt]# head -n5 /etc/passwd |awk -F: ‘{print $1}’ #已冒号为分割,打印第一列
root
bin
daemon
adm
lp
[root@localhost opt]# head -n5 /etc/passwd |awk -F: ‘{print $2}’ #已冒号为分割,打印第二列
x
x
x
x
x
-v的用法:变量赋值
[root@localhost home]# fs=“:”;awk -v FS=$fs -v OFS=“+” ‘{print $1,$3}’ /etc/passwd
#fs的是:然后使用-v给FS赋值=:,输入的时候FS是:,-v给OFS赋值输出的时候变量为+,然后打印第一列和第三列
root+0
bin+1
daemon+2
adm+3
lp+4
a=3
b=4
num=
(
a
w
k
−
v
a
=
"
(awk -v a="
(awk−va="a" -v b=“$b” ‘BEGIN{print a + b}’)
把shell的变量传给awk.
[root@localhost ~]#awk -v FS=‘:’ -v OFS='’ ‘{print $1,$3}’ /etc/passwd
root0
bin1
daemon2
adm3
lp4
sync==5
[root@localhost ~]#echo $PATH | awk -v RS=‘:’ ‘{print $1}’
#默认就是换行输出,不需要改
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin
BEIGIN模式指定:
head -n5 /etc/passwd|awk ‘BEGIN{FS=“:”};{print $5}’
—BEGIN模式在awk执行前改变分隔符,执行过程中,以“:”分割,打印指定内容
head -n5 /etc/passwd|awk ‘BEGIN{FS=“:”};{print $3}’
条件判断打印:
awk -F: ‘$3>500{print $0}’ /etc/passwd
#uid大于500的
awk -F: ‘!($3>10){print $0}’ /etc/passwd
#取反,uid小于10的行,所有列
awk -F: ‘{if ($3>500){print $0}}’ /etc/passwd
#使用了if语句,内部条件(),外部条件{},整个加{}作为一条语句执行,相当于嵌套语法
awk的三元表达式与精准筛选用法:
awk的三元表达式继承了java的用法,格式与Java相似
格式:awk ‘(条件表达式)?(A表达式或者值):(B表达式或者值)’
awk -F: ‘{max=($3>=$4)?$3:$4;{print max,$0}}’ /etc/passwd|sed -n ‘1,6p’
比较passwd文件中以":"为分割的第三个和第四个字段的大小,
max=($3>=$4)?$3:$4:这将变量 max 设置为输入行字段 3 和 4 之间的最大值。
? : 运算符是 if-else 语句的简写,因此此行等效于 if ($3 >= $4) { max=$3 } else { max=$4 }
取比较结果的最大值,赋值给变量max,并且输出max行的所有内容,然后打印其中的1-6行;
awk的精准筛选:
$n(> < ): 用于对比数值
$n~“字符串”: 代表第n个字段包含某个字符串
$n!~“字符串”: 代表第n个字段不包含某个字符串
$n"字符串": 代表第n个字段为某个字符串
$n!=“字符串”: 代表第n个字段不为某个字符串
$NF: 代表最后一个字段
实例1:输出第七个字段包含“bash”所在行的第一个字段和最后一个字段
awk -F: ‘$7~“bash” {print
1
,
1,
1,NF}’ /etc/passwd
实例2:输出第七个字段不包含“nologin”所在行的第一个字段和最后一个字段
awk -F: ‘$7!~“nologin” {print
1
,
1,
1,NF}’ /etc/passwd
实例3:指定第六个字段为/home/dn,第七个字段为/bin/bash,输出满足这些条件所在行的第一个和最后一个字段
awk -F: ‘($6==“/home/dn”)&&($7==“/bin/bash”){print
1
,
1,
1,NF}’ /etc/passwd
[root@localhost ~]# awk -F: ‘$7==“/bin/bash” {print $0}’ /etc/passwd #第七行=/bin/bash
root❌0:0:root:/root:/bin/bash
dn❌1000:1000:dn:/home/dn:/bin/bash
[root@localhost ~]# awk -F: ‘$7!=“/bin/bash” {print $0}’ /etc/passwd #取反
bin❌1:1:bin:/bin:/sbin/nologin
daemon❌2:2:daemon:/sbin:/sbin/nologin
adm❌3:4:adm:/var/adm:/sbin/nologin
awk的分隔符用法:
RS 指定行分隔符:
awk从文件中读取资料时,将根据RS的定义把资料切割成许多条记录,
而awk一次仅读入一条记录进行处理。内置变量RS的预设值是"\n" 也就是换行。
也可以使用BEGIN模式在操作前进行行分隔符的改变
echo $PATH
echo $PATH | awk ‘BEGIN{RS=“:”};{print NR,$0}’ —以":"分割,分割后逐行打印内容和行号
指定输出的分隔符:
OFS:输出内容的列分隔符。(
n
=
n=
n=n用于激活,否则不生效,n必须存在)
对于输出时改变分隔符,我们常用到tr,awk,它们都可以实现在输出内容改变原本的分隔符
tr改变分隔符输出
echo a b c d
echo a b c d|tr " " “:”
awk改变输出分隔符
echo a b c d|awk ‘{OFS=“:”;$1=$1;print $0}’
echo a b c d|awk ‘BEGIN{OFS=“:”};{$2=$2;print $0}’
awk结合数组运用
awk中定义数组打印:
awk ‘BEGIN{a[0]=10;a[1]=20;a[2]=30;print a[1]}’
awk中的数组形成遍历
awk ‘BEGIN{a[0]=10 ; a[1]=20 ; a[2]=30;for(i in a)print i,a[i]}’ #在awk中打印变量不需要加$
处理文件去重统计:
cat test3.txt
aaa
aaa
bbb
ccc
aaa
bbb
aaa
awk '{a[KaTeX parse error: Expected 'EOF', got '}' at position 5: 1]++}̲;END{for(i in a…
awk -v debug=1 ‘{print “Processing line”, NR, “with value”, $1; a[$1]++};END{for(i in a){print “Result for value”, i, “is”, a[i]}}’ test2.txt
检测运行机制
原理:a[$1]初始为0,a[$1]++后即为1,
而这里awk中的a[$1]++最终的值是由test2.txt文本内容有多少行决定的,awk本身就是编程语言,不要按照shell来
文本逐行读取完毕后再执行END中的命令
awk会按行读取文件test2.txt的内容,然后逐个单词存储到数组a中。
每个单词都作为数组a的索引,所以每个单词都对应一个值,初始值为0。
读取文件的第一行,单词为 aaa,此时a[aaa]为0,执行 a[$1]++ 后,a[aaa]变成1。
读取文件的第二行,单词为 aaa,此时a[aaa]为1,执行 a[$1]++ 后,a[aaa]变成2。
读取文件的第三行,单词为 bbb,此时a[bbb]为0,执行 a[$1]++ 后,a[bbb]变成1。
读取文件的第四行,单词为 ccc,此时a[ccc]为0,执行 a[$1]++ 后,a[ccc]变成1。
读取文件的第五行,单词为 aaa,此时a[aaa]为2,执行 a[$1]++ 后,a[aaa]变成3。
读取文件的第六行,单词为 bbb,此时a[bbb]为1,执行 a[$1]++ 后,a[bbb]变成2。
读取文件的第七行,单词为 aaa,此时a[aaa]为3,执行 a[$1]++ 后,a[aaa]变成4。
最终,数组a中的元素值变成:a[aaa]=4,a[bbb]=2,a[ccc]=1。
实例引用
简单的日志分割
awk ‘{print $1, $7, $9}’ /var/log/messages
在这个命令中,我们使用单引号将awk命令的操作包含起来。
$1、$7和$9是awk的内置变量,分别表示每行日志文件中的第1、第7和第9个字段。
通过使用print命令,我们将这些字段分别打印出来,以空格分隔。
最后,我们指定日志文件的路径/var/log/messages,awk会自动对文件中的每行进行处理并输出结果。
只分割前两行内容的第一个和第四个字段
awk ‘NR<=2{print $1, $4}’ /var/log/messages
取小数点几位和取整数
result=KaTeX parse error: Expected '}', got 'EOF' at end of input: …#取小数点2位 result=(awk ‘BEGIN{printf “%.F”, 2.331*2.542}’) # 不取小数点,只取整数
提取host.txt主机名后再放回host.txt文件
1 www.kgc.com
2 mail.kgc.com
3 ftp.kgc.com
4 linux.kgc.com
5 blog.kgc.com
cat file.txt | awk -F ‘[ .]+’ ‘{print $2}’ >> host.txt
统计磁盘总共使用容量:
df | tail -n +2 | grep -v tmpfs | awk ‘{sum+=$4} END{print "磁盘可用容量:“sum/1024/1024"G”}’
统计/etc下文件总大小
ls -l /etc | awk ‘/^-/{sum+=$5} END{print "文件总大小:“sum/1024"M”}’
CPU使用率
top -b -n 1
-b 告诉 top 以批处理模式运行,没有交互界面,这意味着它将输出结果到控制台一次,然后退出。
-n 1 指定 top 在退出之前应运行的迭代次数。在这种情况下,它只运行一次。
us 表示用户空间占用 CPU 百分比,sy 表示内核空间占用 CPU 百分比
[root@localhost network-scripts]# sum=$(top -b -n 1 | grep -w st |awk ‘{print $2+$4}’)
[root@localhost network-scripts]# echo $sum
3.1
统计内存:
#使用量
memory_used=$(free -m | grep “Mem:” |awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 3: 3 }̲') #总计 memory_t…(free -m | grep “Mem:” |awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 3: 2 }̲') #打印内容: echo …memory_used
echo '当前内存的总量’KaTeX parse error: Expected 'EOF', got '#' at position 14: memory_total #̲计算百分比 z=(echo “scale=2;
m
e
m
o
r
y
u
s
e
d
/
{memory_used}/
memoryused/{memory_total}*100”|bc)
echo
z
b
=
z b=
zb=(echo $z | awk -F ‘.’ ‘{print $1}’)
echo
b
e
c
h
o
"
当前的使用占比
:
b echo "当前的使用占比:
becho"当前的使用占比:{b}%"
if [
b
−
l
t
90
]
t
h
e
n
e
c
h
o
"
内存的使用量正常
:
b -lt 90 ] then echo "内存的使用量正常:
b−lt90]thenecho"内存的使用量正常:{b}%
else
echo “内存的使用量为:”$b"大于90%,请注意!"
fi
监控硬盘:
[root@localhost home]# df -h | grep -w centos-root | awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 5}̲' | tr -d "%" 1…(df -h | grep -w centos-root | awk ‘{print $5}’) | tr -d “%”
[root@localhost home]# echo KaTeX parse error: Expected 'EOF', got '#' at position 28: …localhost home]#̲ b=(echo “$a” | sed ‘s/%//g’)
[root@localhost home]# echo $b
16