sed和awk

1、sed的简单介绍

sed是流编辑器,用于处理文件
sed是一行一行读取文件内容并按照要求进行处理,把处理后的结果输出到屏幕

在这里插入图片描述
1、首先sed读取文件中的一行内容,把其保存在一个临时缓存区中(也称为模式空间)
2、然后根据需求处理临时缓冲区中的行,完成后把该行发送到屏幕上

总结:
1.由于sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会直接修改原文件
2.Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作,对文件进行过滤和转换操作

2、sed的使用方法

sed常见的语法格式有两种,一种叫命令行模式,另一种叫脚本模式

2.1 命令行格式

语法格式

sed [options] '处理动作' 文件名

常见选项

选项说明备注
-e进行多项(多次)编辑直接在命令列模式上进行 sed 的动作编辑
-n取消默认输出在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。
-r使用扩展正则表达式sed 的动作支持的是延伸型正规表示法的语法。(默认是基础正规表示法语法)
-i原地编辑(修改源文件)直接修改读取的文件内容,而不是输出到终端
-f指定sed脚本的文件名直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 sed 动作

常见的处理动作
以下所有的动作都要在单引号里

动作说明备注
‘p’打印
‘i’在指定行之前插入内容类似vim里的大写O
‘a’在指定行之后插入内容类似vim里的小写o
‘c’替换指定行所有内容
‘d’删除指定行

2.2 案例

文件准备

#a.txt
root:x:0:0:root:/root:/bin/bash
adm:x:3:4:adm:/var/adm:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4: adm:/var/adm:/sbin/nologin
lp:x:4:7:tp:/var/spool/lpd:/sbin/nologin
298374837483
172.16.0.254 
10.1.1.1

打印文件内容

sed '' a.txt	#对文件什么都不做,但是由于没有-n参数,因此还会将文件的内容打印到屏幕

sed -n 'p' a.txt	#打印每一行,并取消默认输出

sed -n '1p' a.txt	#打印第一行

sed -n '2p' a.txt	#打印第二行

sed -n '1,5p' a.txt	#打印1-5行

sed -n '$p' a.txt	#打印最后一行

增加文件内容(单独成行)

sed '$a99999' a.txt		#文件最后一行后面增加内容

sed 'a99999' a.txt		#文件每行后面增加内容

sed '5a99999' a.txt		#文件第5行后面增加内容

sed '$i99999' a.txt		#文件最后一行的前面增加内容

sed 'i99999' a.txt		#文件每行的前一行增加内容

sed '6i99999' a.txt		#文件第6行前一行增加内容

sed '/^uucp/ihello'		#以uucp开头行的前一行插入内容

#在第1行前连续插入3行内容(第1中写法只会将要插入的内容看成一行,应该遵循第2种写法)
sed -n '1i\hello\world\888' a.txt
结果: 
helloworld888

sed '1i\
> hello\
> world\
> fl' a.txt
结果:
hello
world
fl

sed '2,4a999' a.txt		#在2-4行的每一行后面一行都增加内容

修改文件内容

sed '5chello world' a.txt	#替换文件第5行的内容

sed 'chello world' a.txt	#替换文件所以内容

sed '1,5chello world' a.txt	#替换文件1到5行内容为hello world,不是1到5行每一行都替换

sed '/^user01/c888888' a.txx #替换user01开头的行

sed如果需要结合正则,需要将正则表达式用斜杠包裹起来,例如:
sed '/^adm/chello fl' a.txt

删除文件内容

sed '1d' a.txt	 #删除文件第一行

sed	'1,5d' a.txt #删除文件1到5行

sed '$d' a.txt	 #删除文件最后一行

sed '/[0-9]/d' a.txt	#删除包含数字的行

sed -r '/([0-9]\.){1,3}[0-9]{1,3}/d' a.txt #删除文件中的ip地址,-r表示支持扩展正则

对文件进行搜索替换操作
语法:sed 选项 's/搜索内容/替换内容/动作' 需要处理的文件
其中,s表示search搜索。斜杠/表示分隔符,可以自定义。动作一般是打印p和全局替换g。如果不加g,一行中有多个匹配到了,只会替换第一个,加g,则全部替换

sed -n 's/root/ROOT/gp' a.txt	#全文搜索root并替换成ROOT

sed -n 's/^#//gp' a.txt	#删除首行以#开头的#,相当于取消注释

sed -n 's@/sbin/nologin@fl@gp' a.txt #将全文中的/sbin/nologin替换为fl
或者写为:sed -n 's/\/sbin\/nologin@fl@gp' a.txt

sed -n '10s@/sbin/nologin@fl@gp' a.txt #将第10行中的/sbin/nologin替换为fl,如果没有,就不处理

sed -n '1,5s/^/#/gp' a.txt	#注释前5行

sed -n 's#\(10.1.1.\)1#\1fl#gp' a.txt	#(10.1.1.)表示\1,把最后一个1替换为fl

其他命令

命令含义
r从另外文件读取内容
w内容另存为
&保存查找串以便在替换串中引用
=打印行号
!对所选行以外的所有行应用命令,放到行数之后
q退出
sed '3r /etc/hosts' a.txt	#将/etc/hosts中的数据读到a.txt的第3行之后的位置
[root@fl Shell]# sed '3r /etc/hosts' a.txt
root:x:0:0:root:/root:/bin/bash
adm:x:3:4:adm:/var/adm:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
::1	localhost	localhost.localdomain	localhost6	localhost6.localdomain6
127.0.0.1	localhost	localhost.localdomain	localhost4	localhost4.localdomain4
127.0.0.1	fl	fl
adm:x:3:4: adm:/var/adm:/sbin/nologin
lp:x:4:7:tp:/var/spool/lpd:/sbin/nologin
298374837483
172.16.0.254 
10.1.1.1

sed '1,5w b.txt' a.txt	#将a.txt中的1-5行保存到b.txt中

sed -n 's/^lp/#&/gp' a.txt	#在以lp开头的前面添加#号 &和\(\)的作用相同
#lp:x:4:7:tp:/var/spool/lpd:/sbin/nologin

sed -n 's/^lp/&#/gp' a.txt	#在以lp开头的后面添加#号
lp#:x:4:7:tp:/var/spool/lpd:/sbin/nologin

sed -n '1,5!p' a.txt #打印非1到5行

sed -ne '/root/p' a.txt -ne '/root/='	#打印root所在的行,并打印行号

sed -e '/^#/d' -e '/^$/d' a.txt	#删除以#开头行(取消注释),删除空行
sed -r '/^#|^$/d' a.txt

2.3 sed结合正则使用

sed 选项 'sed’命令或者正则表达式或者地址定位文件名

1.地址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的合。
2.如果没有指定地址. sed将外理输入文件的所有行。

正则说明案例
/key/查询包含关键字的行sed -n ‘/root/p’ a.txt
/key1/,/key2/匹配包含两个关键字之间的行sed -n ‘/^adm/, /^mysql/p’ a.txt
/key/,X从匹配关键字的行开始到文件第x行之间的行(包含关键字所在行)sed -n ‘/^ftp/,7p’
x,/key/从文件的第x行开始到与关键字的匹配行之间的行
x,y!不包含x到y行
sed -nr '/^lp | ^mysql/p' a.txt	#找出以lp或者mysql开头的行

sed -n '/sync/,8p' a.txt #打印sync所在的行到第8行之间所有的行,闭区间

sed -n '3,/^halt/p' a.txt #从第3行开始,打印以halt开头的行之间的所有内容,闭区间

2.4 脚本格式

用法

#sed -f scripts.sh file  //使用脚本处理文件
建议使用	./sed.sh file

脚本的第一行写上
#!/bin/sed -f

注意事项

脚本文件是一个sed的命令行清单。’ commands’
在每行的末尾不能有任何空格、制表符(tab)或其它文本。
如果在一行中有多个命令,应该用分号分隔。
不需要且不可用引号保护命令
#号开头的行为注释

3、awk的简单介绍

awk概述
awk是一种编程语言,主要用于在linux/unix下对文本和数据进行处理,是linux/unix 下的一个工具。数据可以来自标准输入、一个或多个文件,或其它命令的输出。
awk的处理文本和数据的方式:逐行扫描文件,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。

awk能干啥?
1、awk用来处理文件和数据的,是类unix下的一个工具,也是一种编程语言
2、可以用来统计数据,比如网站的访问量,访问的IP量等等
3、支持条件判断,支持for和while循环

4、awk的使用方法

4.1 命令行模式

语法结构

awk 选项 '命令部分' 文件名

特别说明:
引用Shell变量需要用双引号引起

常用选项介绍

  • -F定义字段分隔符,默认分割符是空格
  • -v定义变量并赋值

‘命名部分说明’

  • 正则表达式,地址定位
'/root/{awk语句}'  		  sed中: '/root/p'
'NR==1,NR==5{awk语句}'	  sed中: '1,5p'
'/^root/,/^ftp/{awk语句}' sed中: '/^root/,/^ftp/p'
  • {awk语句1;awk语句2;…}
'{print $0;print $1}'  sed中: 'p'
'NR==5{print $0}'	   sed中: '5p'
注: awk命令语句间用分号间隔
  • BEGIN…END…
'BEGIN{awk语句};{处理中};END{awk语句}'
'BEGIN{awk语句};{处理中}'
'{处理中};END{awk语句}'

4.2 脚本模式

脚本编写

#!/bin/awk -f 
一以下是awk引号里的命令清单,不要用引号保护命令,多个命令用分号间隔
BEGIN{FS=":"}
NR==1,NR==3{print $1"\t"$NF}
...

脚本处理

方法1:
awk 选项 -f awk的脚本文件 需要处理的文本文件
awk -f awk.sh filename

sed -f sed.sh -i filename

方法2:
./awk的脚本文件(或者绝对路径) 需要处理的文本文件
./awk.sh filename

./sed.sh filename 

5、awk内部相关变量

变量变量说明备注
$0当前处理的所有记录
$1,$2,$3…$n文件中每行以间隔符分割的不同字段,间隔符默认是空格awk -F:‘{print $1,$3}’
NF当前记录的字段数(列数)awk -F:‘{print NF}’
$NF最后一列$(NF-1)表示倒数第二列
FNR/NR行号
FS定义间隔符‘BEGIN{FS=“:”};{print $1,$3}’
OFS定义输出字段分隔符,默认空格‘BEGIN{OFS=“\t”};print $1,$3}’
RS输入记录分割符,默认换行‘BEGIN{RS=“\t”};{print $0}’
ORS输出记录分割符,默认换行‘BEGIN{ORS=“\n\n”};{print$1,$3}’
FILENAME当前输入的文件名

5.1 案例

文本准备

head /etc/passwd > 1.txt
tail -3 /etc/passwd >> 1.txt

[root@fl Shell]# cat 1.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
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
fl:x:1000:1000::/home/fl:/bin/bash
yunwei:x:1001:1001::/home/yunwei:/bin/bash
user1:x:1002:1002::/home/user1:/bin/bash
awk '{print $0}' 1.txt   #打印每一行(因为没有分隔符,$0表示文本中的每一行)

awk 'NR==1,NR==5{print $0}'	1.txt   #打印1-5行,同下
awk 'NR>=1 && NR<=5{print $0}' 1.txt

awk 'NR==1 || NR==5{print $0}' 1.txt   #打印1和5行

awk -F: '{print $1,$(NF-1),$NF}' 1.txt   #打印每一行以冒号分割的第一列,倒数第二列和最后一列

awk -F: '{print NF}' 1.txt   #每一行以冒号分割,并打印每一行的列数

awk -F: '/root/{print $1,$NF}' 1.txt   #打印包含root的,以冒号分割的第一行和最后一行

awk 'NR>=1 && NR<=5 && /^root/{print $0}' 1.txt   #打印1-5行中以root开头的行

awk 'BEGIN{FS=":";OFS="@"};{print $1,$NF}' 1.txt   #打印以冒号分割的第一列和最后一列,列与列之间用@作为分隔符,同下
awk 'BEGIN{FS=":";OFS="@"};{print $1"@"$NF}' 1.txt   #分隔符要用双引号引起来

6、awk工作原理

awk -F: '{print $1,$3}' /ect/passwd
  1. awk使用一行作为输入,并将这一 行赋给内部交量50,每行也可称为一个记录,以换行符(RS)结束
  2. 每行被间隔符:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始
  3. awk使用print函数打印字段,打印出来的字段会以空格分隔,因为$1,$3之间有一个逗号。逗号比较特殊,它映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格
  4. awk处理完一行后, 将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕

7、awk进阶使用

格式化的输出print和printf

print函数	类似echo
[root@fl Shell]# date | awk '{print "Month: "$2 "\nYear: "$NF}'
Month: Feb
Year: 2023

printf函数	类似echo -n
[root@fl Shell]# awk -F: 'NR==1,NR==3{printf "%-15s %-10s %-15s\n",$1,$2,$3}' /etc/passwd
root            x          0              
bin             x          1              
daemon          x          2 


%s 字符类型 strings	
%d 数值类型
- 表示左对齐,默认是右对齐
%-15s  表示向左对齐15个字符,如果不够,用空格填充
printf默认不会在行尾自动换行,需要我们手动加上\n

awk变量定义

[root@fl Shell]# awk -v NUM=3 -F: 'NR==1{print NUM}' /etc/passwd
3
[root@fl Shell]# awk -v NUM=3 -F: 'NR==1{print $NUM}' /etc/passwd
0

[root@fl Shell]# awk -v num=1 'BEGIN{print num}'
1
[root@fl Shell]# awk -v num=1 'BEGIN{print $num}'


注意:
awk中调用定义的变量不需要加$,因为$+数字表示特定分隔符分割后的某一列

awk中BEGIN…END使用

BEGIN:表示在程序开始之前执行
END:表示所有文件处理完后执行
用法:‘BEGIN{开始处理之前};{处理中};END{处理结束后}’

案例1:打印最后一列和倒数第二列(登录shell和家目录)

[root@fl Shell]# awk -F: 'BEGIN{printf "Login_shell\tLogin_home\n********************\n"};{printf $NF"\t"$(NF-1)"\n"};END{printf "*******************\n"}' 1.txt
Login_shell	Login_home
********************
/bin/bash	/root
/sbin/nologin	/bin
/sbin/nologin	/sbin
/sbin/nologin	/var/adm
/sbin/nologin	/var/spool/lpd
/bin/sync	/sbin
/sbin/shutdown	/sbin
/sbin/halt	/sbin
/sbin/nologin	/var/spool/mail
/sbin/nologin	/root
/bin/bash	/home/fl
/bin/bash	/home/yunwei
/bin/bash	/home/user1
*******************

案例2:打印/etc/passwd里的用户名、家目录以及登录shell

[root@fl Shell]# awk -F: 'BEGIN{OFS="\t\t";print "u_name\t\th_dir\t\tshell\n********************"};{printf "%-20s %-20s %-20s\n",$1,$(NF-1),$NF};END{print "********************"}' 1.txt
u_name		h_dir		shell
********************
root                 /root                /bin/bash           
bin                  /bin                 /sbin/nologin       
daemon               /sbin                /sbin/nologin       
adm                  /var/adm             /sbin/nologin       
lp                   /var/spool/lpd       /sbin/nologin       
sync                 /sbin                /bin/sync           
shutdown             /sbin                /sbin/shutdown      
halt                 /sbin                /sbin/halt          
mail                 /var/spool/mail      /sbin/nologin       
operator             /root                /sbin/nologin       
fl                   /home/fl             /bin/bash           
yunwei               /home/yunwei         /bin/bash           
user1                /home/user1          /bin/bash           
********************

awk和正则的综合运用
这里只写了之前没有出现过的正则符号

运算符说明
~匹配
!~不匹配

案例

awk 'NR==1,/^lp/{print $0}' 1.txt   #打印从第一行开始,到以lp开头的行中间所有的行,闭区间

awk '/^lp/,NR==10{print $0}' 1.txt   #打印以lp开头的行,到第10行中间所有的行,闭区间

awk '/^root/ || /^lp/{print $0}' 1.txt   #打印以root开头或者以lp开头的行

awk 'NR>=1 && NR <=5 && $0 ~ /bash$/{print $0}' 1.txt   #打印1-5行中以bash结尾的行

案例3:打印IP地址

方法1:
[root@fl Shell]# ifconfig eth0 | awk 'NR==2{print $0}' | awk -F[' ']+ '{print $3}'
192.168.0.207

方法2:
[root@fl Shell]# ifconfig eth0 | grep -w 'inet' | awk -F[' ']+ '{print $3}'
192.168.0.207

方法3:
[root@fl Shell]# ifconfig eth0 | awk -F"[ ]+" '/inet/{print $3}' | awk 'NR==1{print $0}'
192.168.0.207

8、awk脚本编程

流程控制语句
if结构

格式:
awk 选项 '正则,地址定位{awk语句}' 文件名
{ if(表达式) {语句1;语句2;...}}

awk -F: '{if($3>=500 && $3<=60000) {print $1,$3} }' /etc/passwd

[root@fl Shell]# awk -F: '{if($3==0) {print $1"是管理员"} }' /etc/passwd
root是管理员

[root@fl Shell]# awk -F: 'BEGIN{if($(id -u)==0) {print "当前用户是admin"}}'
当前用户是admin

if…else结构

格式:
{if(表达式) {语句1;语句2;...} else {语句1;语句2;...}}

[root@fl Shell]# awk -F: 'NR==1,NR==3{if($3==0) {print $1"是管理员"} else {print $1"不是管理员"}}' /etc/passwd
root是管理员
bin不是管理员
daemon不是管理员

[root@fl Shell]# awk -F: 'BEGIN{if($(id -u)!=0) {print "当前用户不是admin"} else {print "当前用户是admin"}}'
当前用户是admin

if…else if…eles结构

格式:
{if(表达式1) {语句1;语句2;...}  else if(表达式2) {语句1;语句2;...} else {语句1;语句2;...}}

[root@fl Shell]# awk -F: '{if($3==0) {print $1"是管理员"} else if($3>=1 && $3<=499 || $3==65534) {print $1"是系统 用户"} else {print $1"是普通用户"}}' 1.txt
root是管理员
bin是系统用户
daemon是系统用户
adm是系统用户
lp是系统用户
sync是系统用户
shutdown是系统用户
halt是系统用户
mail是系统用户
operator是系统用户
fl是普通用户
yunwei是普通用户
user1是普通用户


[root@fl Shell]# awk -F: '{if($3==0) {i++} else if($3>=1 && $3<=499 || $3==65534) {j++} else {k++}};END{print "管 理员的个数为:"i"\n系统用户的个数为:"j"\n普通用户的个数为"k}' 1.txt
管理员的个数为:1
系统用户的个数为:9
普通用户的个数为3

循环语句

打印1-5
awk 'BEGIN{for(i=1;i<=5;i++) {print i}}'
awk 'BEGIN{i=1;while(i<=5) {print i; i++}}'

打印1-10中的奇数
awk 'BEGIN{for(i=1;i<=10;i+=2) {print i}}'
awk 'BEGIN{i=1;while(i<=10) {print i; i+=2}}'

计算1-5的和
awk 'BEGIN{for(i=1;i<=5;i++) {sum+=i};{print sum}}'
awk 'BEGIN{i=1;while(i<=5) {sum+=i;i++};{print sum}}'

[root@fl Shell]# awk 'BEGIN{for(i=1;i<=5;i++) {for(j=1;j<=i;j++) {printf j};{print}}}'
1
12
123
1234
12345

8.1 案例

统计系统中各个类型的shell

[root@fl Shell]# awk -F: '{shells[$NF]++};END{for(i in shells) {print i"\t"shells[i]}}' /etc/passwd
/bin/sync	1
/bin/bash	4
/sbin/nologin	17
/sbin/halt	1
/sbin/shutdown	1

统计该服务器的所有访问状态

[root@fl Shell]# netstat -napt | grep '^tcp' | awk -F'[ ]+' '{states[$6]++};END{for(i in states) {print i":"states[i]}}'
LISTEN:5
ESTABLISHED:9

统计访问网站的每个IP的数量

ss -antp | grep 80 | awk -F: '!/LISTEN/{ip_count[$(NF-1)]++};END{for(i in ip_count) {print i":"ip_count[i]}}' | sort -k2 -rn | head
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值