Linux三剑客

三剑客

grep

grep 参数

-i 忽略字符大小写
-o 仅显示匹配到的字符串本身
-v  显示不能被匹配到的行
-E 支持使用扩展的正则表达式元字符
-q 不输出任何信息
-c 统计文本中与之相关的有几行
参数效果
-i忽略大小写
-l只列出匹配行所在的文件名
-n在每一行前面加上它在文件中的相对行号
-c显示成功匹配的行数
-s禁止显示文件不存在或文件不可读的错误信息
-q静默?
-v反向查找,只显示不匹配的行
-R,-r递归针对目录
–color颜色
-o只显示匹配的内容
-Bprint NUM lines of leading context
-Aprint NUM lines of trailing context
-Cprint NUM lines of output contesx
-c

将passwd重定向到pass.txt
统计文本中与root相关的行有多少
-c 计数

grep -i -c root ./pass.txt
-n

-n 显示行号

输出文本非空行的内容

grep '^$'  -n -v pass.txt

显示匹配内容在文件的哪一行

[root@wzb ~]# grep -n 'root' /etc/passwd /etc/group
/etc/passwd:1:root:x:0:0:root:/root:/bin/bash
/etc/passwd:10:operator:x:11:0:operator:/root:/sbin/nologin
/etc/group:1:root:x:0:

[root@wzb ~]# vim /etc/passwd +10  #+n 可以直接去到相应的行编辑,可用在查看报错修改等地方
-R

查找出目录下所有的相关的文件

这里找在这个目录下所有文件中带有=~的文件

:的左边是文件,右边是相关内容的行号

[root@wzb ~]# grep -R '=~' /home/wzb/practice/shell/
/home/wzb/practice/shell/nginx_select.sh:elif [[ ! "$n" =~ [1-3] ]];then
/home/wzb/practice/shell/useradd_04.sh:	if [[ ${num} =~ ^[1-9][0-9]+$ || -n ${num} || ${num} =~ [1-9] ]];then

另一种方法

[root@wzb ~]# grep  '=~' /home/wzb/practice/shell/*
/home/wzb/practice/shell/lamp_or_lnmp.sh:[[ ! "$num" =~ [1-3] ]] && {
/home/wzb/practice/shell/nginx_select.sh:elif [[ ! "$n" =~ [1-3] ]];then
-l

-l 列出含有所指定参数的文件,不显示具体内容

[root@wzb ~]# grep -l 'root' /etc/passwd /etc/shadow /etc/hosts
/etc/passwd
/etc/shadow
-v

反向查找,只显示不匹配的行

[root@svr7 shell]# cat txt1
root
wzb
123
root
[root@svr7 shell]# grep -v 'root' txt1
wzb
123
grep 查看上下文

-C2 查看上下文2行 context

-B2 查看上2行 before

-A2 查看下2行 after

[root@wzb ~]# grep -C2 'root' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
--
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

正则表达式

通过 grep 来理解一下正则表达式

[root@wzb tongzi]# grep '^root' /etc/passwd  #找出以root开头的行
root:x:0:0:root:/root:/bin/bash
[root@wzb tongzi]# grep '^[rc]oot' /etc/passwd  #找出以root或coot开头的行
root:x:0:0:root:/root:/bin/bash
[root@wzb tongzi]# grep '^[^ab]oot' /etc/passwd  #找出开头不是 aoot 和 boot 的行
root:x:0:0:root:/root:/bin/bash

显示所有 # 开头的行

grep  '^#' /etc/vsftpd/vsftpd.conf

-v 取反 显示没有被注释的行

grep -v '^#' /etc/vsftpd/vsftpd.conf

grep -r 递归针对目录

扩展正则表达式 grep -E

扩展正则表达式ERE集合

扩展正则必须使用grep -E才能生效

字符作用
+匹配前一个字符1次或多次,前面字符至少出现1次
[😕]+匹配括号内的":“或者”/"字符1次或多次
?匹配前一个字符0次或1次,前面字符可有可无
|(竖线)表示或者,同时过滤多个字符串
()分组过滤,被括起来表示一个整体
a{n,m}匹配前一个字符最少n次,最多m次
a{n,}匹配前一个字符最少n次
a{n}匹配前一个字符正好n次
a{,m}匹配前一个字符最多m次

素材文件

[root@test /home/wzb/my_prac]# cat 2022-4-20 
god
goooooooooooooooooood
goooooooood
glad
good
goooooooood
gd
x
y
love 123 love
love 1
love 11 love
lovelove
+

+号 匹配前一个字符1次或多次

[root@test /home/wzb/my_prac]# grep -E '+g' 2022-4-20 
god
goooooooooooooooooood
goooooooood
glad
good
goooooooood
gd

?号 匹配前一个字符0次或1次

[root@test /home/wzb/my_prac]# grep -E "g?d" 2022-4-20 
god
goooooooooooooooooood
goooooooood
glad
good
goooooooood
gd
|

| 符:或者的意思
找出文本带有x或y的行

[root@test /home/wzb/my_prac]# grep -E "x|y" 2022-4-20 
x
y
()

()括号,分组过滤被括起来的内容,括号内的内容表示一个整体
\1 :表示从左侧起,第一个括号中的模式所匹配到的字符
\2 : 表示第二个括号
找出文本中带有good或者glad的行

[root@test /home/wzb/my_prac]# grep -E "g(oo|la)d" 2022-4-20
glad
good

找出文本中含有两个love的行

[root@wzb my_prac]# grep -E "(l..e).*\1" 2022-4-20 
love 123 love
love 11 love
lovelove

效果等同于

[root@wzb my_prac]# grep -E "(l..e).*(l..e)" 2022-4-20 
love 123 love
love 11 love
lovelove
{}

{n,m}匹配次数
匹配 o 字符 ,最少2次,最多4次

[root@wzb my_prac]# grep -E "o{2,5}" 2022-4-20 
goooooooooooooooooood
goooooooood
good
goooooooood

-m m次匹配后停止

[root@wzb my_prac]# grep -E -m 2 "yu" pass.txt 
yu
yu2

找出两位数或者三位数

grep -E "[0-9]{2,3}" pass.txt 

发现会有四位数甚至更多
仅仅找出两位数或三位数,不包含其他位数

grep -E "\<[0-9]{2,3}\>" pass.txt

找出文件中以空格开头的行
空格:[[:space:]]

[root@wzb my_prac]# grep -E "^[[:space:]].*" 2022-4-20 
    1
		1
 11

在passwd文件中,找出用户名和shell(解释器)相同的用户
以 非冒号 开头的行 到冒号就结束 即判断用户名
[^:]+ :读取非冒号的字符一次或多次

[root@wzb my_prac]#  grep -E "^([^:]+\>).*\1$" pass.txt 
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
grep & 正则 查找IP

这里只找到了1个ip

这个错误是因为索引为1的变量被重复引用,所以只有4个数字都相同的ip才会被识别

[root@wzb ~]# grep -E '([0-9]{1,3})\.\1.\1.\1' /etc/sysconfig/network-scripts/ifcfg-ens33 
DNS1=114.114.114.114

正确的方式

[root@wzb ~]# grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}' /etc/sysconfig/network-scripts/ifcfg-ens33 
IPADDR=192.168.92.5
NETMASK=255.255.255.0
GATEWAY=192.168.92.2
DNS1=114.114.114.114

查找网卡文件下,本机的IP地址

[root@wzb ~]# grep -E '^IPA' /etc/sysconfig/network-scripts/ifcfg-ens33 | grep -E -o '([0-9]{1,3}\.){3}[0-9]{1,3}' 
192.168.92.5

sed

参数

sed :对文件或者数据流进行加工处理

语法:sed [选项] [sed内置命令字符] [输入文件]

参数选项解释
-n取消默认sed的输出,常与sed内置命令p一起用
-i直接将修改结果写入,不用-i,sed修改的是内存数据
-e多次编辑,不需要管道符
-r支持正则扩展

内置字符

sed常用内置命令字符

sed内置命令字符解释
aappend,对文本追加,在指定行后面添加一行/多行文本
ddelete,删除匹配行
iinsert,表示插入文本,在指定前添加一行/多行文本
pprint,打印匹配行的内容,通常p与-n一起用
s/正则/替换内容/g匹配正则内容,然后替换内容(支持正则),结尾g代表全局匹配
rread,将文件的内容插入到指定行的后面
w将指定内容另存为
c替换

sed匹配范围

范围解释
空地址全文处理
单地址指定文件某一行
/pattern/被模式匹配到的每一行
范围区间10,20 10到20行 , 10,+5第10行向下5行 , /pattern1/,/pattern2/
步长1~2 表示1、3、5、7奇数行,2~2表示2、4、6、8偶数行

参数的使用

-n & p
sed -n '2,4p' user # 输出2-4行
sed -n '2p;4p' user # 输出第2行和第4行
sed -n '3,+1p' user # 输出第3行以及后面1行
sed -n '/^root/' user # 输出以root开头的行
sed -n '/root/p' user # 输出包含root的行
sed -nr '/^root|^bin/p' user # 输出以root或者bin开头的行(|是扩展正则,需要r选项)
d (删除)
sed '3,5d' a.txt # 删除第3行到第5行
sed '/xml/d' a.txt	# 删除与xml相关的行 
sed '/xml/!d' a.txt	# 删除与xml不相关的行
sed '/^install/d' a.txt	# 删除以install开头的行
sed '$d' a.txt	# 删除最后一行
sed '/^$/d' a.txt	# 删除空行
s///(替换)

cat /etc/passwd > pass.txt
将 pass.txt 中前10行 的 bin 用户 改为 C

[root@wzb practice]# sed -r '1,10s/^bin/C/g' pass.txt

将前10行bin开头的用户改为C,将m开头的改为M

[root@wzb practice]# sed -r -e '1,10s/^bin/C/g' -e '1,10s/^m/M/' pass.txt

内置字符的使用

r
	r /etc/hosts  #读取相应文件写入
	sed -r '2r /etc/hosts' a.txt	#从第2行开始读入
	sed -r '/2/r /etc/hosts' a.txt	#匹配到2的行,开始读入
w
    w /home/wzb/cc.txt  #将文件另存为
    sed -r '/north/w newfile' datafile	#将有关north的行另存为
    sed -r '/3,$w/w newfile' datafile	#将第3行到最后另存为
a
	sed -r '2a 123' /etc/hosts  #在第2行后面追加
i	
	sed -r '2i 123' /etc/hosts #在第2行前面追加
c
	sed -r '2c 123' /etc/hosts #将第2行替换

=(输出行号)

输出行号

这个文件有4行

[root@svr7 shell]# sed -n "$=" txt1
4

和root相关的行在第1和第4行

[root@svr7 shell]# sed -n "/root/=" txt1
1
4

h H g G 暂存和取用

指令效果
h将内容覆盖至暂存空间
H将内容追加至暂存空间
g将暂存空间的内容覆盖至模式空间
G将暂存空间的内容追加至模式空间

将第1行内容放在暂存空间,然后G使暂存空间的内容追加

效果就是将第1行的内容复制到了最后一行

[root@wzb practice]# sed -r '1h;$G' pass_short.txt 

与上面相似,将内容覆盖至暂存空间后删除

效果是将第一行的内容剪切到了最后一行

[root@wzb practice]# sed -r '1{h;d};$G' pass_short.txt 

将第1行…然后将第2行至最后的所有的行都覆盖为暂存空间的内容

效果就是所有行都变为第1行

[root@wzb practice]# sed -r '1h;2,$g' pass_short.txt 

将第1行覆盖,2-3行追加,

效果就是在最后追加了前3行的内容

[root@wzb practice]# sed -r '1h;2,3H;$G' pass_short.txt 

空间内容互换(反人类)

[root@wzb practice]# sed -r '4h;5x;6G' u.txt

awk

awk 擅长文本格式化,且输出格式化后的结果

awk 内置变量

内置变量解释
FS输入字段分隔符,默认为空白字符
OFS输出字段分隔符,默认为空白字符
RS输入记录分隔符(输入换行符),指定输入时的换行符
ORS输出记录分隔符(输出换行符),输出时用指定符号替代换行符
NFNF:number of Field,当期行的字段的个数(即当前行被分割成了几列),字段数量
NRNR:number of records,行号,当前处理的文本的行号
FNRFNR:各文件分别计数的行号
FIIENAME当前文件名
ARGC命令行各个参数
ARGV数组,保存的事命令行所给定的各个参数
$n指定分隔符后,当前记录的第n个字段
$0完整的输入记录
FS字段分隔符,默认是空格
内置变量解释
$n指定分隔符后,当前记录的第n个字段
$0完整的输入记录
FS字段分隔符,默认是空格
NF(Number of fields)分割后,当前行一共有多少个字段
NR(Number of records)当前记录数,行数
更多内置变量可以man手册查看man awk

awk参数

参数解释
-F指定分割字段符
-v定义或修改一个awk内部的变量
-f从脚本文件中读取awk命令
[root@wzb my_prac]# cat awk.txt  
1 2 3 4
5 6 7 8
9 a b c
d e f g

输出全部内容

[root@wzb my_prac]# awk '{print $0}' awk.txt 
1 2 3 4
5 6 7 8
9 a b c
d e f g

输出第1列的内容

[root@wzb my_prac]# awk '{print $1}' awk.txt 
1
5
9
d

输出多行数据

[root@wzb my_prac]# awk '{print $1,$3}' awk.txt 
1 3
5 7
9 b
d f

pass

[root@wzb my_prac]# awk '{print "第一列:"$1,"第二列:$3"}' awk.txt 
第一列:1 第二列:$3
第一列:5 第二列:$3
第一列:9 第二列:$3
第一列:d 第二列:$3

指定分隔符

[root@wzb my_prac]# cat awk2.txt 
1#2#3#4
5#6#7#8
9#a#b#c
d#e#f#g
[root@wzb my_prac]# awk -F '#' '{print $1,$3}' awk2.txt 
1 3
5 7
9 b
d f

显示文件第2、3行

[root@wzb my_prac]# awk 'NR==2,NR==3{print $0}' awk1.txt 
5 6 7 8
9 a b c

显示行号

[root@wzb my_prac]# awk '{print NR,$0}' awk1.txt 
1 1 2 3 4
2 5 6 7 8
3 9 a b c
4 d e f g

显示第一列和倒数第二列

[root@wzb my_prac]# awk '{print $1,$(NF-1)}' awk1.txt 

输出第2至第4行

[root@wzb my_prac]# awk 'NR==2,NR==4{print}' awk1.txt 
5 6 7 8
9 a b c
d e f g

利用awk取出ip地址

[root@wzb my_prac]# awk 'NR==2{print $2}' ip.txt
192.168.92.5

OFS:指定输出分隔符
指定输出的分隔符为—

[root@wzb my_prac]# sed "1,5p" pass1.txt -n | awk -F  ":" -v OFS="---" '{print $1,$NF}'
root---/bin/bash
bin---/sbin/nologin
daemon---/sbin/nologin
adm---/sbin/nologin
lp---/sbin/nologin

制表符 \t

[root@wzb my_prac]#  sed "1,5p" pass1.txt -n | awk -F  ":" -v OFS="\t" '{print $1,$NF}'
root	/bin/bash
bin	/sbin/nologin
daemon	/sbin/nologin
adm	/sbin/nologin
lp	/sbin/nologin

在这里插入图片描述

打印前三行

[root@wzb my_prac]# awk 'NR<4{print $0}' pass1.txt 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

指定输入和输出符

[root@wzb my_prac]# sed "1,5p" -n pass.txt | awk -v FS=':' -v OFS='---' '{print NR,NF,$1}' 
1---7---root
2---7---bin
3---7---daemon
4---7---adm
5---7---lp

FNR 处理多个文件显示行号

每个文件都重新处理行号

[root@wzb practice]# awk '{print FNR,$0}' 1 2
1 a
2 b
3 c
1 w
2 x
3 y
4 z

读取空格,将空格作为换行符输出

awk -v RS=' ' '{print NR,$0}' mess_#

ORS,修改每一行的结束符号,将换行改为@

[root@wzb my_prac]#awk -v ORS="@" '{print NR,$0}' mess_#
1 1 2 3 4@2 5 6 7 8@3 9 a b c@4 d e f g@

ORS 将文件中的内容变为一行

[root@wzb practice]# awk 'BEGIN{ORS=""} {print $0}' mess_# 
1 2 3 45 6 7 89 a b cd e f g

OR 将文件分为多行

[root@wzb practice]# cat 1 
a:b:c
111 222 333 444 555

[root@wzb practice]# awk -F : 'BEGIN {RS=" "} {print $0}' 1
a:b:c
111
222
333
444
555

FILENAME

显示awk正在处理文件的名字

文件名为 version.txt mess_#

[root@wzb my_prac]# awk '{print FNR,FILENAME,$0}' mess_# version.txt 
1 mess_# 1 2 3 4
2 mess_# 5 6 7 8
3 mess_# 9 a b c
4 mess_# d e f g
1 version.txt CentOS    Linux    release  add  7.9.2009 (Core)

变量ARGC、ARGV

BEGIN

[root@wzb my_prac]# awk 'BEGIN{print "开始用awk"} {print $0}' mess_# 
开始用awk
1 2 3 4
5 6 7 8
9 a b c
d e f g

ARGV

ARGV是作为一个列表

发现ARGV中存了 awk 、执行文件名、空格

[root@wzb my_prac]# awk 'BEGIN{print "开始"} {print ARGV[0],$0}' mess_# 
开始
awk 1 2 3 4
awk 5 6 7 8
awk 9 a b c
awk d e f g

再次执行,发现一次输出的是 awk,文件名,文件名

awk 'BEGIN{print "开始"} {print ARGV[0],ARGV[1],ARGV[2]}' mess_#  pass_short.txt 
开始
awk mess_# pass_short.txt
awk mess_# pass_short.txt
awk mess_# pass_short.txt
awk mess_# pass_short.txt

自定义变量(外部变量)

-v 指定变量

[root@wzb my_prac]# awk -v myname="wzb" 'BEGIN{print "我的名字是?",myname}'
我的名字是? wzb

间接引用shell变量

[root@wzb my_prac]# myname=wzb
[root@wzb my_prac]# awk -v ment=$myname 'BEGIN{print ment} {print $0}' mess_# 
wzb
1 2 3 4
5 6 7 8
9 a b c
d e f g

awk格式化

image-20220425102249875

printf

不会输出换行符

[root@wzb my_prac]# awk '{printf $0 }' article_1 
床前明月光疑是地上霜举头望明月低头思故乡

给 printf 添加格式

[root@wzb my_prac]# awk '{printf "%s\n",$0 }' article_1  
床前明月光
疑是地上霜
举头望明月
低头思故乡

awk的 格式替换符 想要修改多个变量,必须传⼊多个

并且awk后若不加上文件数据,必须添加 BEGIN

%d 表示十进制数字

[root@wzb my_prac]# awk 'BEGIN{printf "%d\n%d\n%d\n%d\n",1,2,3,4}'
1
2
3
4

案例

[root@wzb my_prac]# awk '{printf "first:%s second:%s thrid:%s fourth:%s\n",$1,$2,$3,$4}' mess_#
first:1 second:2 thrid:3 fourth:4
first:5 second:6 thrid:7 fourth:8
first:9 second:a thrid:b fourth:c
first:d second:e thrid:f fourth:g

案例

%s\t 格式化字符串,添加制表符,4个空格

-:向左对齐,25个字符长度

[root@wzb my_prac]#awk -F ":" 'BEGIN{printf "%-10s\t %-10s\t %-10s\t %-10s\t %-10s\t %-10s\t %-s\n","用户名","密码","UID","GID","用户注释","用户家目录","用户使用的解释器"} {printf "%-10s\t %-10s\t %-10s\t %-10s\t %-10s\t %-20s\t %s\n",$1,$2,$3,$4,$5,$6,$7}' pass_short.txt
用户名       	 密码        	 UID       	 GID       	 用户注释      	 用户家目录     	 用户使用的解释器
root      	 x         	 0         	 0         	 root      	 /root               	 /bin/bash
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
root      	 x         	 0         	 0         	 root      	 /root               	 /bin/bash
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
sync      	 x         	 5         	 0         	 sync      	 /sbin               	 /bin/sync
shutdown  	 x         	 6         	 0         	 shutdown  	 /sbin               	 /sbin/shutdown
halt      	 x         	 7         	 0         	 halt      	 /sbin               	 /sbin/halt
mail      	 x         	 8         	 12        	 mail      	 /var/spool/mail     	 /sbin/nologin
operator  	 x         	 11        	 0         	 operator  	 /root               	 /sbin/nologin

image-20220425140248752

awk模式

BEFIN、END

案例

[root@wzb my_prac]# awk 'BEGIN{print "处理文本之前的操作"}{print $0}END{print "done"}' mess_# 
处理文本之前的操作
1 2 3 4
5 6 7 8
9 a b c
d e f g
done

打印前三行的内容

[root@wzb my_prac]# awk 'NR<4{print $0}' pass1.txt 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

!= 的用法,不输出第一行

[root@wzb my_prac]# awk 'NR!=1{print $0}' mess_# 
5 6 7 8
9 a b c
d e f g

正则表达式的用法

找出以wzb开头的用户

用法:awk /正则表达式/{动作} 文件

[root@wzb my_prac]# awk '/^wzb/{print $0}' pass1.txt 
wzb:x:1000:1000:wzb:/home/wzb:/bin/bash
wzb123:x:1004:1004::/home/wzb123:/bin/bash

案例

[root@wzb my_prac]# awk -F ":" '/^wzb/{print $1,$NF}' pass1.txt 
wzb /bin/bash
wzb123 /bin/bash

逻辑操作符和复合模式

~ 表示正则

[root@wzb practice]# awk -F ":" '$1~/root/ && $3 <= 15' /etc/passwd
...
[root@wzb practice]# awk -F ":" '$1~/root/ || $3 <= 15' /etc/passwd
...
[root@wzb practice]# awk -F ":" '!($1~/root/ || $3 <= 15)' /etc/passwd
...

awk脚本编程

if

判断root用户

[root@wzb practice]# awk -F ":" '{if($3==0) {print $1 " is admin"}}' /etc/passwd
root is admin

统计用户数量 要注意大括号的位置 行处理为一个部分,END为一个部分

[root@wzb practice]# awk -F ":" '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd
47

注意大括号的位置

[root@wzb practice]# awk -F ":" '{if($3==0){count++} else{i++}} END{print "管理员个数:"count;print "系 统用户数:" i}' /etc/passwd
管理员个数:1
系统用户数:53

if多分支语句

[root@wzb practice]# awk -F ":" '{if($3==0){i++} else if($3>999){k++}else{j++}} END{print "管理员个数:"i;print "普通用户个数:"k;print "系统用户:"j}' /etc/passwd
管理员个数:1
普通用户个数:6
系统用户:47
while

while简单应用

[root@wzb practice]# awk 'BEGIN{ i=1;while(i<=3){print i;i++} }'
1
2
3

案例

[root@wzb practice]# awk -F ":" '/^root/{i=1;while(i<=7){print $i;i++}}' pass1.txt 
root
x
0
0
root
/root
/bin/bash

每行打印10次

[root@wzb practice]# awk -F ":" '{i=1;while(i<=10){print $0;i++}}' /etc/passwd

案例

[root@wzb practice]# cat b.txt 
111 222
333 444 555
666 777 888 999

案例 依次打印每一列

将一行打印完再打印下一行的内容

[root@wzb practice]# awk '{i=1;while(i<=NF){print $i;i++}}' b.txt 
111
222
333
444
555
666
777
888
999
for

c风格for

[root@wzb practice]# awk 'BEGIN{for(i=1;i<=5;i++){print i}}'
1
2
3
4
5

每行打印10次

[root@wzb practice]#  awk '{ for(i=1;i<=10;i++){print $0} }' b.txt 

依次打印每一列

[root@wzb practice]#  awk '{ for(i=1;i<=NF;i++){print $i} }' b.txt 
111
222
333
444
555
666
777
888
999

awk & 数组

案例

[root@wzb practice]# awk -F ":" '{username[i++]=$1} END{print username[0]}' /etc/passwd
root

案例

[root@wzb practice]# awk -F ":" '{username[x++]=$1} END{for(i in username) {print i,username[i]}}' pass1.txt0 root
1 bin
2 daemon

统计passwd中的解释器 for语句

[root@wzb practice]# awk -F ":" '{list[$NF]++} END{for(i in list){print i,list[i]}}' /etc/passwd
/bin/sync 1
/bin/bash 6
/sbin/nologin 45
/sbin/halt 1
/sbin/shutdown 1

网站访问状统计

[root@wzb practice]# netstat -ant | grep ":80" | awk '{list[$NF]++} END{print $NF,list[$NF]}'
LISTEN 3

统计当前访问ip的数量

[root@wzb ~]# ss -ant | grep ':80' | awk '{list[$(NF-1)]++} END{for (i in list) {print i,list[i]}}'
*:8081 1
*:8082 1
*:80 1

add

-k2 表示根据第二列排序

[root@wzb ~]# ss -ant | grep ':80' | awk '{list[$(NF-1)]++} END{for (i in list) {print i,list[i]}}' | sort -k2 -rn

脚本编程实战

统计Nginx日志中某一天不同ip的访问量

这里指在2022.8.6这一天

[root@wzb logs]# grep '06/Aug/2022' text.log | awk '{list[$1]++} END{ for (i in list){print i,list[i]} }'
192.168.92.1 12
192.168.92.5 3
192.168.92.160 4

another

[root@wzb logs]# awk '/06\/Aug\/2022/{print $0}' text.log | awk '{list[$1]++} END{for (i in list){print i,list[i]}}'
192.168.92.1 12
192.168.92.5 3
192.168.92.160 5
统计用户名为4个字符的用户
[root@wzb practice]# awk -F ":" '$1~ /^....$/{count++;print $1} END{print "count is: " count}' /etc/passwd
root
sync
halt
mail
dbus
abrt
qemu
sssd
sshd
test
count is: 10

若要统计10个字符就会很麻烦

[root@wzb practice]# awk -F ":" 'length($1)==4{count++;print $1} END{print "count is "count}' /etc/passwd

awk命令执行流程

使用 grep 找出关于 sbin/nologin 的行

[root@wzb my_prac]# grep "sbin/nologin" pass_short.txt -n
2:bin:x:1:1:bin:/bin:/sbin/nologin
3:daemon:x:2:2:daemon:/sbin:/sbin/nologin
4:adm:x:3:4:adm:/var/adm:/sbin/nologin
5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
7:bin:x:1:1:bin:/bin:/sbin/nologin
8:daemon:x:2:2:daemon:/sbin:/sbin/nologin
9:adm:x:3:4:adm:/var/adm:/sbin/nologin
10:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
14:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
15:operator:x:11:0:operator:/root:/sbin/nologin

现用 awk 来实现

//之间要写正则,要用"“将”/"转为普通的符号

[root@wzb my_prac]# awk '/\/sbin\/nologin/{print NR,$0}' pass_short.txt 
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
7 bin:x:1:1:bin:/bin:/sbin/nologin
8 daemon:x:2:2:daemon:/sbin:/sbin/nologin
9 adm:x:3:4:adm:/var/adm:/sbin/nologin
10 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
14 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
15 operator:x:11:0:operator:/root:/sbin/nologin

多个正则,打印出 以bin开头 到 以daemon开头 的行

发现若存在多个 daemon 的情况下,会输出到最后一个daemon

[root@wzb my_prac]# awk '/^bin/,/^daemon/{print $0}' pass_short.txt 
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

企业实现Nginx日志

1、统计访客日志的ip数量

awk '{print $1}' my.log  | sort -n

去重

[root@wzb logs]# awk '{print $1}' my.log  | sort -n | uniq
127.0.0.1
192.168.92.1
192.168.92.5

计算有多少行

[root@wzb logs]# awk '{print $1}' my.log  | sort -n | uniq | wc -l
3

2、查看访问最频繁的前10个ip

 首先可以查看每个ip出现的次数

	uniq -c 	显示次数

	sort -nr	从大到小排列

	head -10	显示前10行
[root@wzb logs]# awk '{print $1}' my.log  | sort -n | uniq -c | sort -nr | head -10
     37 192.168.92.1
     24 127.0.0.1
      6 192.168.92.5

awk练习

打印出普通用户的用户和家目录

普通用户的d大于1000

[root@wzb my_prac]# awk -F ":" '$3>=1000{print $1,$(NF-1)}' pass1.txt 
nfsnobody /var/lib/nfs
wzb /home/wzb
test /home/test
tom /home/tom
itheima /home/itheima
wzb123 /home/wzb123

给文件的前5行添加“#”

[root@wzb my_prac]# awk 'NR<6{print "#",$0}' article_1 
# 床前明月光
# 疑是地上霜
# 举头望明月
# 低头思故乡
# 床前明月光

查看练习文本

依次是 人名 区号 电话号码 三次捐款的数额

[root@wzb my_prac]# cat tel.txt 
Mike Harrington:[510] 548-1278:250:100:175

Christian Dobbins:[408] 538-2358:155:90:201

Susan Dalsass:[206] 654-6279:250:60:50

Archie McNichol:[206] 548-1348:250:100:175

Jody Savage:[206] 548-1278:15:188:150

Guy Quigley:[916] 343-6410:250:100:175

Dan Savage:[406] 298-7744:450:300:275

Nancy McNeil:[206] 548-1278:250:80:75

John Goldenrod:[916] 348-4278:250:100:175

Chet Main:[510] 548-5258:50:95:135

Tom Savage:[408] 926-3456:250:168:200

Elizabeth Stachelin:[916] 440-1763:175:75:300


显示所有电话号码

[root@wzb my_prac]# awk -F ":" '{print $2}' tel.txt | awk '!/^$/{print $2}'
548-1278
538-2358
654-6279
548-1348
548-1278
343-6410
298-7744
548-1278
348-4278
548-5258
926-3456
440-1763

第二种方法

-F “[ :]” 指定分隔符是“空格”或者":"

!/^$/ 将空字符不显示

[root@wzb my_prac]# awk -F "[ :]" '!/^$/{print $4}' tel.txt 
548-1278
538-2358
654-6279
548-1348
548-1278
343-6410
298-7744
548-1278
348-4278
548-5258
926-3456
440-1763

显示Tom的电话

通过 正则 /^Tom/ 来找到与Tom相关的行

[root@wzb my_prac]# awk '/^Tom/{print $0}' tel.txt | awk -F ":" '{print $2}' | awk '{print $2}'
926-3456

显示Nancy的姓名、区号、电话

[root@wzb my_prac]# awk -F "[ :]" '/^Nancy/{print $1,$2,$3,$4}' tel.txt 
Nancy McNeil [206] 548-1278

显示D开头的姓

$2~/^D/ 对第2列使用正则

[root@wzb my_prac]# awk -F "[ :]" '$2~/^D/{print $2}' tel.txt 
Dobbins
Dalsass

显示区号是 916 的人名

[root@wzb my_prac]# awk -F ":" '$2~/\[916\]/{print $1}' tel.txt 
Guy Quigley
John Goldenrod
Elizabeth Stachelin

显示Mike的捐款信息,在每一次捐款钱加上”$“

格式化输出

[root@wzb my_prac]# awk -F ":" '$1~/^Mike/{printf "$%s $%s $%s\n",$(NF-2),$(NF-1),$(NF)}' tel.txt 
$250 $100 $175

显示所有人的 姓 + 逗号 + 名

[root@wzb my_prac]# awk -F ":" '{print $1}' tel.txt | awk '!/^$/{printf "%s,%s\n",$1,$2}'
Mike,Harrington
Christian,Dobbins
Susan,Dalsass
Archie,McNichol
Jody,Savage
Guy,Quigley
Dan,Savage
Nancy,McNeil
John,Goldenrod
Chet,Main
Tom,Savage
Elizabeth,Stachelin

删除文件的空白行

[root@wzb my_prac]# awk '!/^$/{print $0}' tel.txt 
Mike Harrington:[510] 548-1278:250:100:175
Christian Dobbins:[408] 538-2358:155:90:201
Susan Dalsass:[206] 654-6279:250:60:50
Archie McNichol:[206] 548-1348:250:100:175
Jody Savage:[206] 548-1278:15:188:150
Guy Quigley:[916] 343-6410:250:100:175
Dan Savage:[406] 298-7744:450:300:275
Nancy McNeil:[206] 548-1278:250:80:75
John Goldenrod:[916] 348-4278:250:100:175
Chet Main:[510] 548-5258:50:95:135
Tom Savage:[408] 926-3456:250:168:200
Elizabeth Stachelin:[916] 440-1763:175:75:300

使用if语句 完整的写法

[root@wzb practice]# awk -F ":" '{ if($3<20){print $3} else {print $1} }' /etc/passwd

sed 案例练习

案例

创建素材文件

[root@wzb my_prac]# cat 2022-4-21 
My name is chaoge.
I teach linux.
I like play computer game.
My qq is 23123123a
My web is www.baidu.com

打印第二行的内容

[root@wzb my_prac]# sed "2p" 2022-4-21 -n
I teach linux.

查看2-3行的内容

[root@wzb my_prac]# sed "2,3p" 2022-4-21 -n
I teach linux.
I like play computer game.

找出与linux相关的行,并打印
-n 输出相关结果

[root@wzb my_prac]# sed "/linux/p" 2022-4-21 -n
I teach linux.

删除有关linux的行
d:删除
i:将修改写入文件

[root@wzb my_prac]# sed "/linux/d" 2022-4-21 -i
[root@wzb my_prac]# cat 2022-4-21 
My name is chaoge.
I like play computer game.
My qq is 23123123a
my web is www.baidu.com

删除第五行之后的所有内容,包括第5行
$:表示结尾
d:表示删除
使用单引号

[root@wzb my_prac]# sed '5,$d' 2022-4-21 -i
[root@wzb my_prac]# cat 2022-4-21
1My name is chaoge.
2I like play computer game.
3My qq is 23123123a
4my web is www.baidu.com

将My 替换为his
s/要被替换的内容/替换的内容/g
g表示全局

[root@wzb my_prac]# sed "s/My/his/g" 2022-4-21 
his name is chaoge.
I teach linux.
I like play computer game.
his qq is 23123123a
his web is www.baidu.com

将My改为his,将linux改为python
用到 -e

[root@wzb my_prac]# sed -e "s/My/his/g" -e "s/linux/python/g" 2022-4-21
me is chaoge.
I teach python.
I like play computer game.
his qq is 23123123a
his web is www.baidu.com

在第二行添加文本
2a:表示在第二行之后添加,那么第三行则显示nice

[root@wzb my_prac]# sed "2a nice" 2022-4-21
My name is chaoge.
I teach linux.
nice
I like play computer game.
My qq is 23123123a
My web is www.baidu.com

在第四行添加nice
i:表示insert,第四行显示nice

[root@wzb my_prac]# sed "4i nice" 2022-4-21
My name is chaoge.
I teach linux.
I like play computer game.
nice
My qq is 23123123a
My web is www.baidu.com

添加多行信息

[root@wzb my_prac]# sed "4i add1\nadd2" 2022-4-21
My name is chaoge.
I teach linux.
I like play computer game.
add1
add2
My qq is 23123123a
My web is www.baidu.com

每一行都添加信息
a后面有无空格都可以

[root@wzb my_prac]# sed "a ==========" 2022-4-21
My name is chaoge.
==========
I teach linux.
==========
I like play computer game.
==========
My qq is 23123123a
==========
My web is www.baidu.com
==========

删除第4行后面所有,包括第4行

 sed "4,$d" 2022-4-21 -i

删除从root开始,到ftp之间的行

sed "/^root/,/^ftp/d" pass.txt

找出网卡的ip

[root@wzb my_prac]# ifconfig ens33 | sed "2p" -n
      inet 192.168.92.5  netmask 255.255.255.0  broadcast 192.168.92.255

sed "s/^inet.*//g"将开头所有字符到 inet 为止的字符替换为空

sed "s/netmask.*//gnetmask之后的所有字符替换为空

[root@wzb my_prac]# ifconfig ens33 | sed "2p" -n | sed "s/^.*inet//g" | sed "s/netmask.*//g"
192.168.92.5 

使用 -e
2s 在第二行中进行替换

[root@wzb my_prac]# ifconfig ens33 | sed -e "2s/^.*inet//gp" -n
 192.168.92.5  netmask 255.255.255.0  broadcast 192.168.92.255
[root@wzb my_prac]# ifconfig ens33 | sed -e "2s/^.*inet//g" -e "2s/net.*//gp" -n
 192.168.92.5 

将空行添加#

将文件中空白字符开头的行,添加注释
原理是将开头的一个空格替换成#,并不是在开头插入一个#

[root@wzb my_prac]# sed -e "s/^[[:space:]]/#/g" 2022-4-21 -e "s/^$/#/g" 2022-4-21 -i
[root@wzb my_prac]# cat 2022-4-21
1
2
3
4
#5
6
#

找出系统版本

找出系统版本
将 release之前的文本和后面的空格再加上第一个读取到的非.的字符,以及后面的所有字符
替换为 第一个读取到的字符 即为 7

[root@wzb my_prac]# sed -r "s/^.*release[[:space:]]([^.]).*/\1/p" /etc/centos-release -n
7

若有多个空格,使用 [[:space:]]* 将多个空格替换

[root@wzb my_prac]# cat version.txt 
CentOS    Linux    release    7.9.2009 (Core)
[root@wzb my_prac]# sed -r "s/^.*release[[:space:]]*([^.]).*/\1/p" version.txt -n
7
[root@wzb my_prac]# sed -r -n  "s/^.*release *(.*)/\1/p" version.txt	# 也可以不用[[:space:]]

删除文件的空白行和注释行

有空格的行无法删除

[root@wzb my_prac]# sed -e "/^$/d" 2022-4-21 -e "/^#/d" 2022-4-21 -i
[root@wzb my_prac]# cat 2022-4-21
1
2
3
4
6
 
   things  

使用分号

sed "/^#/d";"/^$/d" 2022-4-21

给文件前三行添加$符号

-r 扩展正则表达式 "\1"需要
先将第一个字符替换为#加读取到的第一个字符

[root@wzb practice]# sed -r '1,3s/(^.)/$\1/' 2022-4-21
$#
$1
$#
2
#
3
4
6
 
   things 

另一种方法
似乎-r 和 -e 无法连用?

错误的

[root@wzb my_prac]# sed "1,3p" 2022-4-21 -n | sed -r "s/(^.)/@\1/p" -n
@#
@1
@#

d 和 +2d 的区别

sed -r '/^adm/,20d' /etc/passwd  # 删除到20行
sed -r '/^adm/,+20d' /etc/passwd  # 再删除20行

修改类似路径的数据

若文件中有类似路径的数据需要修改

[root@wzb shell]# cat u.txt 
/usr/local/nginx

尝试

无法识别

[root@wzb shell]# sed -r 's//usr/local//home/wzb/' u.txt 
sed:-e 表达式 #1,字符 8:“s”的未知选项

换一个方式 就可以了

[root@wzb shell]# sed -r 's@/usr/local@/home/wzb@' u.txt 
/home/wzb/nginx

n 获取下一行命令

这里发现若文件中有2个相关行,只会对靠后的行进行相关操作

sed -r '/adm/{n;s/sbin/uuu/}'	#找到adm之后的第一个匹配行,进行替换
sed -r '/adm/{n;n;s/sbin/uuu/}'	#找到adm之后的第二个匹配行,进行替换

删除注释行

[root@wzb practice]# cat u.txt 
#123
	#
   #
123
123
123#123

操作

\t 表示tab

有0个或多个空格&有0个或多个tab

[root@wzb practice]# sed -r '/^[ \t]*#.*/d' u.txt 
123
123
123#123

删除以//开头的行

[root@wzb practice]# sed '/^[ \t]*\/\//d' u.txt 
123
123
123//123

指定位置添加#,已有的不再添加

[root@wzb practice]# cat u.txt 
#123
#123
123
123
	#123
   #123
	#
 #

操作

[root@wzb practice]# sed -r 's/^[ \t#]*/#/' u.txt 
#123
#123
#123
#123
#123
#123
#
#

在末尾添加数据、变量的使用

[root@wzb practice]# sed -r "\$a$name" u.txt 也可以

[root@wzb practice]# sed -r '$a'"$name" u.txt 
123
123
wzb123

替换成自己+xx

[root@wzb applicaton_of_sed]# cat t1.txt 
192.168.92.5
192.168.92.131
aa
bb
cc
11
22
33
192.168.92.5
192.168.92.5
192.168.92.5
192.168.92.9

答案

需要添加 -r 否则 \1无法被识别

[root@wzb applicaton_of_sed]# sed -r 's/(192.168.92.5)/\1localhost/g' t1.txt 
192.168.92.5localhost
192.168.92.131
aa
bb
cc
11
22
33
192.168.92.5localhost
192.168.92.5localhost
192.168.92.5localhost
192.168.92.9

将内容替换为与之后面紧接的数字

如 digit33要被改为333

[root@wzb applicaton_of_sed]# cat t2.txt 
aa digit3
digit44bb
12digitb

答案

[0-9]即为 0-9的遍历

[root@wzb applicaton_of_sed]#  sed -r 's/digit([0-9])/\1\1/g' t2.txt 
aa 33
444bb
12digitb

将所有的loverable替换成loves

[root@wzb applicaton_of_sed]# cat t3.txt 
loverable
loverable123
lovera
love
loverable
loverable
loverable

答案

[root@wzb applicaton_of_sed]# sed -r 's/(lover)able/\1s/g' t3.txt 
lovers
lovers123
lovera
love
lovers
lovers
lovers

打印奇数行或偶数行

[root@wzb applicaton_of_sed]# cat t4.txt 
1
2
3
4
5
6
7
8
9

答案

意为从第一行开始,每两行输出一次,即为奇数行

那么偶数行就可以改为sed -n '2~2p' t4.txt

[root@wzb applicaton_of_sed]# sed -n '1~2p' t4.txt 
1
3
5
7
9

当一行包含,就修改内容

当一行包含east…west就添加aaabbb

[root@wzb applicaton_of_sed]# cat t5.txt 
east 123 123 123 west
east  a   b   c  west
east  z   z   z  wesz
east yes  west   yes

答案

[root@wzb applicaton_of_sed]# sed -r -n 's/(^east.*west.*$)/\1aaabbb/p' t5.txt 
east 123 123 123 westaaabbb
east  a   b   c  westaaabbb
east yes  west   yesaaabbb

指定范围修改内容

让包含start的行到包含end的行之间的aa bb替换成AA BB

[root@wzb applicaton_of_sed]# cat t6.txt 
aa bb
start
aa bb
abc abc
aa bb
aabb
end
start
aabb

答案

/start/表示与start相关的行

/start/,/end/表示

image-20220601103817946

打完与之相关行的命令后直接打s///

[root@wzb applicaton_of_sed]# sed '/start/,/end/s/aa bb/AA BB/g' t6.txt 
aa bb
start
AA BB
abc abc
AA BB
aabb
end
start
aabb

输出33后的所有行

[root@wzb applicaton_of_sed]# cat t1.txt 
192.168.92.5
192.168.92.131
aa
bb
cc
11
22
33
192.168.92.5
192.168.92.5
192.168.92.5
192.168.92.9

答案

$:直接到结尾

[root@wzb applicaton_of_sed]# sed -n '/33/,$p' t1.txt 
33
192.168.92.5
192.168.92.5
192.168.92.5
192.168.92.9

输出33后两行

答案

[root@wzb applicaton_of_sed]# sed -n '/33/,$p' t1.txt | sed '1,3p' -n
33
192.168.92.5
192.168.92.5

不懂

[root@wzb applicaton_of_sed]# sed -n -r '/33/{N;N;p;q}' t1.txt 
33
192.168.92.5
192.168.92.5

image-20220603150124467

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值