所谓三剑客就是linux中三个可以用linux正则表达式的命令
- grep 过滤
- sed 取行 替换
- awk 取列
环境准备
# passwd.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
grep
格式:grep 选项 正则 文件
作用:在文件中找到符合正则条件的行
选项
- -v 取反
- -i 不区分大小写
- -n 显示匹配到的行在源文件中的行号
- -o 只输出匹配到的内容
- -E 扩展正则
- -w 按单词匹配
- -A -B -C 可以显示匹配行的前后几行 -A3 后三行 -B3 前三行 -C3前后三行
- -P 可以使用Perl正则语法
例子
# 以noLogin结尾的 不区分大小写 可以去掉-i试试
[root@centos76 data]# grep -i "noLogin$" passwd.txt
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
# 加上-v试试 变成不以nologin结尾的了
[root@centos76 data]# grep -iv "noLogin$" passwd.txt
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
# 再加上-n试试 显示了在源文件中的行号
[root@centos76 data]# grep -ivn "noLogin$" passwd.txt
1:root:x:0:0:root:/root:/bin/bash
2:
7:sync:x:5:0:sync:/sbin:/bin/sync
8:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
9:
10:halt:x:7:0:halt:/sbin:/sbin/halt
grep -E 相当于egrep 可以使用linux正则表达式中的扩展正则
# -o 只显示匹配到的内容 而不是显示整行
[root@centos76 data]# grep -ino "noLogin$" passwd.txt
3:nologin
4:nologin
5:nologin
6:nologin
11:nologin
# -w 按单词匹配 所以用nologin可以匹配到 用no不行
[root@centos76 data]# grep -w "nologin" passwd.txt
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
[root@centos76 data]# grep -w "no" passwd.txt
[root@centos76 data]#
sed
作用
流编辑器 可以对文本进行增删改查
格式
sed [OPTION]... '取什么 取到后做什么' [input-file]...
选项
- -n 取消默认输出
- -r 扩展正则
- -i 直接修改文件
- -e 多次编辑
sed -n '1,3p' passwd.txt
取1到3行并打印
# 准备实验对象passwd.txt
[root@centos76 data]# cat /etc/passwd > passwd.txt
[root@centos76 data]# sed -n '1,3p' passwd.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
-n选项取消默认打印,去掉后会发现1到3行打印了两遍,其他行也都打印了,自己试试体会下。
'1,3p' 这个就是格式中的脚本部分,作用是:取什么 取到后做什么
1,3表示取1到3行 p表示取到后打印
改成'4p'自己试下。
sed -n '/root/p' passwd.txt
取到包含root的行并打印
[root@centos76 data]# sed -n '/root/p' passwd.txt
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
//之间的内容 世界是正则表达式
sed "1,10d" passwd.txt
删除1到10行并打印剩下的行
[root@centos76 data]# sed "1,10d" passwd.txt
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
nginx:x:997:995:nginx user:/var/cache/nginx:/sbin/nologin
ocean:x:1000:1000::/home/ocean:/bin/bash
执行上面这些删除命令后,你会发现passwd.txt源文件并没有发生变化,如果想修改源文件,需要加-i参数,-i.bak会先备份后修改源文件,建议修改前备份
sed -i.bak "1,10d" passwd.txt
备份后在源文件中删除1到10行,真实删除
[root@centos76 data]# sed -i.bak "1,10d" passwd.txt
[root@centos76 data]# wc passwd.txt
11 20 560 passwd.txt
[root@centos76 data]# wc passwd.txt.bak
21 30 945 passwd.txt.bak
建议:操作前备份,操作后检查
sed "s/nologin/NOLOGIN/g" passwd.txt
把nologin替换成NOLOGIN
s/查找的内容/替换的内容/g s表示替换 g表示全局,///可以替换成###,@@@,只要可以分割即可//之间实际上是正则表达式
[root@centos76 data]# sed "s/nologin/NOLOGIN/g" passwd.txt
games:x:12:100:games:/usr/games:/sbin/NOLOGIN
ftp:x:14:50:FTP User:/var/ftp:/sbin/NOLOGIN
nobody:x:99:99:Nobody:/:/sbin/NOLOGIN
systemd-network:x:192:192:systemd Network Management:/:/sbin/NOLOGIN
dbus:x:81:81:System message bus:/:/sbin/NOLOGIN
polkitd:x:999:998:User for polkitd:/:/sbin/NOLOGIN
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/NOLOGIN
postfix:x:89:89::/var/spool/postfix:/sbin/NOLOGIN
chrony:x:998:996::/var/lib/chrony:/sbin/NOLOGIN
nginx:x:997:995:nginx user:/var/cache/nginx:/sbin/NOLOGIN
ocean:x:1000:1000::/home/ocean:/bin/bash
sed '2a hello' passwd.txt
第二行之后添加一行hello是第三行
sed '2i hello' passwd.txt
第二行之前插入一行hello是第二行
sed 获取ip地址
sed默认不支持扩展正则 加上-r支持扩展正则
s#A#B#g 用来把A替换成B
# ipv4
> A=`^.*inet (([0-9]{1,3}\.){3}[0-9]{1,3}).*$`
> B=`\1` 分组引用,引用`([0-9]{1,3}\.){3}[0-9]{1,3}`
[root@centos76 ~]# ip address show ens33|grep "inet "|sed -r 's#^.*inet (([0-9]{1,3}\.){3}[0-9]{1,3}).*$#\1#g'
192.168.100.100
# ipv6
> A=`^.*inet6 (([0-9a-fA-F]{,4}:){5}[0-9a-fA-F]{,4}).*$`
> B=`\1` 分组引用,引用`([0-9a-fA-F]{,4}:){5}[0-9a-fA-F]{,4}`
[root@centos76 ~]# ip address show ens33|grep "inet6"|sed -r 's#^.*inet6 (([0-9a-fA-F]{,4}:){5}[0-9a-fA-F]{,4}).*$#\1#g'
fe80::6ac3:3104:7003:e3fe
小结
-
sed -n {1,4p} 文件名
按行查找-取什么:1-4行,取到后做什么:p打印。 -
sed -n '/A/p' 文件名
按正则查找-取什么 :能匹配正则A的行,取到后做什么:p打印。 -
sed "s/A/B/g" 文件名
替换-把正则A匹配的内容替换成B,A中可以分组,B中可以引用。
awk
作用
用-F指定的分割符将文件分割,分割后
1代表第一列
NF代表最后一列
$(NF-1)代表倒数第二列
NF 列数
NR 行号
然后执行program指定的程序
格式
awk [options] -f progfile [--] file ...
awk [options] [--] 'program' file ...
下面讲的都是这个格式
'program'
的格式是 '条件{动作}'
选项
- -F 指定分割符
awk '/games/' passwd.txt
只有条件没有动作 表示过滤符合条件的行
条件可以是正则/正则/
awk默认支持扩展正则
也可以是范围NR==1,NR==3
,
分割表示1到3行
也可以是多个条件NR>=1 && NR<=3
[root@centos76 data]# awk '/games/' passwd.txt
games:x:12:100:games:/usr/games:/sbin/nologin
[root@centos76 data]# awk 'NR==1,NR==3' passwd.txt
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
awk -F':' '{print $1}' passwd.txt
只有动作没有条件 表示所有的行都要执行该program
这里指定了分割符为:,用分隔符把passwd.txt中的每一行分割成多个列
之后执行'{print $1}'这段程序
就是打印第一列的内容
[root@centos76 data]# awk -F':' '{print $1}' passwd.txt
games
ftp
nobody
systemd-network
dbus
polkitd
sshd
postfix
chrony
nginx
ocean
# 这里中间可以加上--
# --的作用是 明确--前面的部分是awk [options]
# 明确--后面的部分是'program' file ...
[root@centos76 data]# awk -F ':' -- '{print $1}' passwd.txt
games
ftp
nobody
systemd-network
dbus
polkitd
sshd
postfix
chrony
nginx
ocean
awk -F ':' 'NR==1,NR==3{print $1}' passwd.txt
既有条件又有动作 表示只对符合条件的行执行对应的动作
[root@centos76 data]# awk -F ':' 'NR==1,NR==3{print $1}' passwd.txt
games
ftp
nobody
例子
sed专业取行
用sed将/etc/passwd文件中第一行到最后一行重定向到passwd.txt
# -n 和 p 配对 -n默认不打印 p打印 结果就是只打印符合条件的
sed -n '1,$p' /etc/passwd > passwd.txt
显示/etc/passwd的第三行到第七行
sed -n '3,7p' /etc/passwd
# 表示单个条件
awk 'NR>=3 && NR<=7' /etc/passwd
# , 表示范围 从第三行到第7行
awk 'NR==3,NR==7' /etc/passwd
awk专业取列
用sed取出passwd.txt中用户名为dbus的行中备注列
dbus:x:81:81:System message bus:/:/sbin/nologin #取出System message bus
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin #取出FTP User
# -r 用来使用增强正则 n和p配对 g
# s#找什么#替换成什么#g
sed -rn 's#([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*)#\5#gp' passwd.txt
[root@centos76 sjk]# sed -rn 's#dbus:([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*)#\4#p' passwd.txt
System message bus
[root@centos76 sjk]# sed -rn 's#ftp:([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*)#\4#p' passwd.txt
FTP User
[root@centos76 sjk]# awk -F: '$1=="dbus"{print $5}' passwd.txt
System message bus
[root@centos76 sjk]# awk -F: '$1=="ftp"{print $5}' passwd.txt
FTP User
使用awk取passwd.txt用户名及家目录并显示行号
[root@centos76 sjk]# awk -F: '{print NR,$1,$6}' passwd.txt |column -t
1 root /root
2 bin /bin
3 daemon /sbin
4 adm /var/adm
passwd.txt中uid>10时 显示整行
[root@centos76 sjk]# awk -F: '$3>10{print NR,$0}' passwd.txt
10 operator:x:11:0:operator:/root:/sbin/nologin
11 games:x:12:100:games:/usr/games:/sbin/nologin
12 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13 nobody:x:99:99:Nobody:/:/sbin/nologin
[root@centos76 data]# awk -F: '$1~/games/{print NR,$0}' passwd.txt
1 games:x:12:100:games:/usr/games:/sbin/nologin