shell三剑客:grep&sed&awk

grep

目的
  • 过滤,查找文档中的内容
分类
  • grep

  • egrep

    • 扩展支持正则

      • \w 所有字母与数字,称为字符[a-zA-Z0-9] ‘l[a-zA-Z0-9]*ve’ === ‘l\w*ve’

      • \W 所有字母与数字之外的字符,称为非字符 ‘love[^a-zA-Z0-9]+’ === ‘love\W+’

  • \b 词边界 ‘\<love\>’ === ‘\blove\b’

  • fgrep

      - 就不支持正则
    
返回值
  • 0 是找到了

    • 表示成功;
  • 1 是没有

    • 表示在所提供的文件无法找到匹配的pattern
  • 2 找到地儿不对

  • 示范

 ## grep 'root' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    operator:x:11:0:operator:/root:/sbin/nologin
 ## echo $?
    0
    
 ## grep 'root1' /etc/passwd  #用户root1并不存在
 ## echo $?
    1
    
 ## grep 'root' /etc/passwd1  #这里的/etc/passwd1文件并不存在
    grep: /etc/passwd1: No such file or directory
 ## echo $?
    2
参数
  • grep -q 静默

    即不显示查找的结果

[root@localhost ~]# grep "5\.." 1.txt
5.1
5.2
5.a
5.b
5..
5...
5.aaa
[root@localhost ~]# grep -q "5\.." 1.txt
[root@localhost ~]# echo $?
0

  • grep -v 取反
[root@localhost ~]# cat 1.txt
5.1
5.2
5.a
5.b
5..
5...
5.aaa
[root@localhost ~]# grep -v "5\.." 1.txt
5...
5.aaa
  • grep -R 可以查目录下面的文件
[root@web shell02]# grep chenfuguo /etc/
grep: /etc/: 是一个目录

[root@web shell02]# grep -R  chenfuguo /etc/
/etc/mtab:/dev/sr0 /run/media/chenfuguo/CentOS\0407\040x86_64 iso9660 ro,nosuid,nodev,relatime,uid=1000,gid=1000,iocharset=utf8,mode=0400,dmode=0500 0 0

  • grep -o 只找到这个关键字就可以
[root@localhost ~]# grep "a" 1.txt
5.a
5.aaa
a
ab
abc
abcd
abcde
abcdef
loveable
ldfadasfsdave
[root@localhost ~]# grep -o  "a" 1.txt
a
a
a
a
a
a
a
a
a
a
a
a
a
a
  • grep -B2前两行

  • grep -A2后两行

  • grep -C2上下两行

  • egrep -l 只要文件名

[root@localhost ~]# egrep -l 'root' /etc/passwd
/etc/passwd
  • egrep -n 带行号
[root@localhost ~]# egrep -n 'xulei' /etc/passwd
43:xulei:x:1000:1000::/home/xulei:/bin/bash

sed

  • Stream EDitor:流编辑

  • sed 是一种在线的、非交互式的编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。

接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;

格式
  • **1 sed 选项 命令 文件 **

  • sed [options] ‘command’ file(s)

  • 2 sed 选项 –f 脚本 文件

    • sed [options] -f scriptfile file(s)
返回值
  • 都是0,对错不管。

  • 只有当命令存在语法错误时,sed的退出状态才是非0

sed和正则表达式
  • 与grep一样,sed在文件中查找模式时也可以使用正则表达式(RE)和各种元字符。正则表达式是括在斜杠间的模式,用于查找和替换,以下是sed支持的元字符。

  • 使用基本元字符集 ^, $, ., *, [], [^], < >,(),{}
    使用扩展元字符集 ?, +, |, ( )

  • 使用扩展元字符的方式:

    • \+ 转义

    • sed -r 加-r

删除命令: d

sed -r '哪些行(正则/行号)干什么(d/r/s/w等等)' 文件名

sed -r '3d' passwd.txt
sed -r '/^root/d' passwd.txt

通过正则匹配词组删除:

# red -ri '/root/d' passwd.txt   # 选项加上i 表示要修改源文件
# sed -r '/root/d' passwd.txt 
  
  通过正则匹配词组删除
  [root@localhost ~]# sed -r '/root/d' passwd 

通过行号删除:

 # sed -r '3d' passwd  # 表示删除第三行
 标准写法:
 # sed -r '3{d}' passwd
  # sed -r '3{d;}' passwd
  
  {存放sed的多个命令} 3{h;d},h暂存空间
    # sed -r '3,$d' passwd 
  
  $最后一行
  删除3到最后一行
  [root@localhost ~]# sed -r '3,$d' passwd 
  root:x:0:0:root:/root:/bin/bash1
  bin:x:1:1:bin:/bin:/sbin/nologin2
替换命令: s

语法:

默认替换匹配行的第一个
# sed -r 's/要替换的内容/新的内容/'  文件名

全部替换
# sed -r 's/要替换的内容/新的内容/g'  文件名
# sed -r 's/root/aofa/g' passwd
全部的root被换掉了。
请思考与下面的命令有区别吗?
# sed -r 's/^root/aofa/' passwd
# sed -r 's/[0-9][0-9]$/&.5/' passwd 
查找双数   结尾的词组
&:替换成    双数.5
&有查询结果的含义。
VI中也有类似功能。

:% s/.*/#&/g
&:查询结果的含义


:% s/\(.*\)/#\1/g
每一行
换成
#每一行
# sed -r 's/(mail)/E\1/g' passwd

()括号组合字符,\1调用括号
sed -r 's#(mail)#E\1#g' passwd

分隔符可以换成井号
读文件命令:r

在当前文件中,读取其他文件“部分”内容。

# sed -r '$r 1.txt' passwd   
# 最后一行,读取新文件1.txt $表示最后一行 r表示读
# sed -r '/root/r ip.txt' passwd
正则搜寻root
在root后面读取新文件

写文件命令:w(另存为)

##### 

```powershell
# sed -r 'w 111.txt' 1.txt

把1.txt全部内容 写入111.txt
#sed -r '/root/w 123.txt' passwd.txt

# 把包含root的行 写入123.txt文件中
# sed -r '1,5w 123.txt' passwd
把1到5行另存为123.txt

追加命令: a(之后)

# sed -r 'a123' passwd
每行后面,都加上123行
# red -r '/^root/a chen:123:x:x:123' passwd.txt
在以root开始的行后面,添加 chen:123:x:x:123
在第二行后面加上三行内容:
sed -r '2a 1111\
> 3333333\
> 444444' passwd

插入命令: i(之前)

# sed -r '2iaaaaaaaa' passwd

在第二行插入新行aaaaaaaaaa

替换整行命令: c

# sed -r '2caaaaaaaa' passwd

把第二行替换成aaaaaaaaa

一行替换多行

是将一行替换成,多行。
[root@localhost ~]# sed -r '2c3333\
> 44444' passwd

获取下一行命令:n

# sed -r '3{n;d}' passwd.txt
# 第三行的下一行,删除
{命令组合}

反向选择: !

sed -r '2,$d' passwd
sed -r '2,$!d' passwd 
# 2到最后一行不删,即第一行删

多重编辑 e

sed -r -e '1,3d' -e '4s/adm/admin/g' passwd 

二、awk

前言

awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。
它支持用户自定义函数和动态正则表达式等先进功能,

awk的处理文本和数据的方式:

它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。
如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),

awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,
分别是Alfred Aho、Peter Weinberger、 Kernighan。

工作原理
awk -F: '{print $1,$3}' /etc/passwd

(1)awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符结束

(2)然后,行被:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始,
最多达100个字段

(3)awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔
成字段并进行处理。该过程将持续到所有行处理完毕

示例:

# awk -F: '{print $0}'   passwd.txt
# awk -F: '{print $1}'   passwd.txt
# awk -F: '{print $2}'   passwd.txt
# awk -F: '{print $3}'   passwd.txt
语法
  • awk [options] ‘commands’ filenames (推荐)

  • options

    • 例如:-F 定义输入字段分隔符,默认的分隔符是空格或制表符(tab)
  • command(时空):

  • BEGIN{} {} END{}

    • BEGIN{}

      • begin发生在行处理前(注意大写)
    • {}

      • 行处理时,读一行执行一次
    • END{}

      • 行处理后
  • 示例

awk -F: 'BEGIN {print 1/2} {print $0} END {print "-------"} ' passwd.txt
awk -F: 'BEGIN {print "awk开始执行"} {print $0} END {print "awk执行结束"} passwd.txt
内部变量
FS

输入字段分隔符(默认空格)

[root@localhost ~]# awk -F: '{print $1, $3}' /etc/passwd | head -1
root 0[root@localhost ~]# awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd | head -1
root x 0[root@localhost ~]# awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd | head -1
root 0

*OFS
输出字段分隔符

[root@localhost ~]# awk -F: '{print $1,$2,$3,$4}' /etc/passwd | head -1
root x 0 0

[root@localhost ~]# awk -F: 'BEGIN{FS=":";OFS="+++"}{print $1,$2,$3,$4}' /etc/passwd | head -1
root+++x+++0+++0
RS(默认不要动)

输入记录(行)分隔符,默认换行符

[root@localhost ~]# awk   '{print $0}' a.txt 
111 222 333 444 555:666:777
[root@localhost ~]# awk 'BEGIN{RS="   "}{print $0}' a.txt 
111
222
333
444
555:666:777
请注意,在此时记录已经不是行的概念了。分隔符由”换行符“换成了”空格“
ORS(默认不要动)

输出记录(行)分隔符,默认换行符

awk 'BEGIN {ORS="++++" } {print $0}' 1.txt
111++++222++++333++++444++++555++++
FNR

多文件独立编号。

即每个文件独立编号,如果一个文件里面混入的有其他文件,则单独设置编号

NR

多文件汇总编号

[root@localhost ~]# awk -F: '{print NR, $0}' /etc/centos-release /etc/hosts
1 CentOS Linux release 7.3.1611 (Core) 
2 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
3 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@localhost ~]# awk -F: '{print FNR, $0}' /etc/centos-release /etc/hosts
1 CentOS Linux release 7.3.1611 (Core) 
1 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
NF

字段总数

[root@localhost ~]# awk -F: '{print NF, $0}'  /etc/passwd
7 root:x:0:0:root:/root:/bin/bash
7 bin:x:1:1:bin:/bin:/sbin/nologin
7 daemon:x:2:2:daemon:/sbin:/sbin/nologin

[root@localhost ~]# awk -F: '{print NF, $NF}'  /etc/passwd
7 /bin/bash
7 /sbin/nologin
7 /sbin/nologin
格式化输出
print 函数
date |awk '{print "Month: " $2 "\nYear: " $1}'
Month: 07月
Year: 2024

\n换行符
想输出文字,用引号

awk -F: '{print "username is: " $1 "\t uid is: " $3}' /etc/passwd | head -1
username is: root	 uid is: 0
awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd  | head -1
	username and uid: root 0!
模式(正则表达)和动作
概念

任何awk语句都由模式和动作组成。模式部分决定动作语句何时触发及触发事件。 如果省略模式部分,动作将时刻保持执行状态。每一行都会有动作。 模式可以是任何条件语句或复合语句或正则表达式。有模式的话,就是对模式对应的行进行动作。

模式:可以是条件测试,正则,复合语句

动作:可以是打印,计算等。

字符串比较
# awk    '/^root/'     /etc/passwd
# awk '$0 ~ /^root/' /etc/passwd  # ~相当于=
# awk '$0!~/^root/' /etc/passwd
# awk -F: '$1 ~ /^root/' /etc/passwd
数值比较

目的:

比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。比较表达式使用关系运算符, 用于比较数字与字符串。

关系运算符

语法:

运算符 含义 示例
< 	小于 			x<y
<= 	小于或等于 	x<=y
== 	等于		 	x==y
!= 	不等于		x!=y
>= 	大于等于 		x>=y
> 	大于 			x>y

示例:

# awk -F: '$3 == 0' /etc/passwd 
# awk -F: '$3 == 1' /etc/passwd 
# awk -F: '$3 < 10' /etc/passwd
== 也可以用于字符串判断
# awk -F: '$7 == "/bin/bash"' /etc/passwd
# awk -F: '$1 == "alice"' /etc/passwd
算术运算

语法:

+ - * / %() ^(幂2^3) 
awk -F: '$3 * 10 > 100' /etc/passwd
多条件

逻辑操作符和复合模式

语法:

&& 逻辑与 a&&b
|| 逻辑或 a||b
! 逻辑非 !a

示例:

# awk -F: '$1~/root/ && $3<=15'	 /etc/passwd
# awk -F:	 '$1~/root/ || $3<=15'		 /etc/passwd
# awk -F:	 '!($1~/root/ || $3<=15)' 	/etc/passwd

范围模式

语法:

awk '/从哪里/,/到哪里/' filename
awk -F: '/adm/,/lpd/' /etc/passwd
从adm到ldp,显示出来,注意避免匹配重复的字段
awk脚本编程
变量

awk调用变量

自定义内部变量 -v:

awk -v user=root -F: '$1 == user' /etc/passwd
-v定义变量

外部变量 “ ‘ ” :

单引号

[root@localhost ~]# heihei=shutdown
[root@localhost ~]# echo $heihei
shutdown
[root@localhost ~]# awk  -F:  '$1 ~ "'"$heihei"'"  '     passwd
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
注意使用单引号时,内部需要用双引转义
条件&判断

if语句

格式:

awk -F: '{if(表达式){语句;语句;...}}'  文件名
awk -F:  '{ if($3==0){ print $1 "是超级管理员"} }'  passwd.txt
root是超级管理员
awk -F:  '{ if($3==0){ print $1 "是超级管理员"} else {print $1 "普通用户"} }'  passwd.txt
root是超级管理员
bin普通用户
daemon普通用户
adm普通用户
lp普通用户
sync普通用户
shutdown普通用户
halt普通用户
mail普通用户
operator普通用户

if…else语句

格式:

awk -F: '{if(表达式){语句;语句;...}else{语句;语句;...}}'  文件名 {if(){}else{}}
awk -F: '{if($3==0){count++} else{i++}} END{print "管理员个数: "count ; print "系统用户数: "i}' /etc/passwd

if…else if…else语句

格式:

{if(表达式1){语句;语句;...}else if(表达式2){语句;语句;...}else if(表达式3){语句;语句;...}else{语句;语句;...}}
if (条件){动作}elseif(条件){动作}else{动作}
if(){}else if  (){}else if(){}else{}
awk -F:  '{if($3==0){print $1," is admin "}else if ($3>999){print $1," is user"}else {print $1, " is sofo user"}}'  /etc/passwd
显示出三种用户的信息 管理员:管理员ID为0 内置用户:用户ID<1000 普通用户: 用户ID>999
循环

while

每行打印十次

awk '{i=1;while(i<=10){print $0;i++}}'   passwd

for

循环打印5个数字:

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

不适用BEGIN可以吗?
{},和END{}可以吗?可以需要有文件。

awk -F: '{ for(i=1;i<=10;i++) {print $0} }' /etc/passwd
将每行打印10次

awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd
打印每一行的每一列

awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd
root
x
0
0
root
/root
/bin/bash
NF是最大列数,循环打印了每一列。
数组

定义数组

需求:将用户名定义为数组的值,打印第一个值

awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd
root

数组遍历

按索引遍历

awk -F: '{username[x++]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd
10 games
11 ftp
12 nobody
13 systemd-bus-proxy
14 systemd-network
15 dbus
16 polkitd
30 chrony
17 abrt
31 ntp
18 unbound
awk编程案例

统计/etc/passwd中各种类型shell的数量

 awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' /etc/passwd

$NF 最后一列的字段内容
{}行处理
把统计的对象,作为索引。每次递增。
Print i  打印索引
Shells[i]  数组加索引,显示的就是值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值