awk/sed/grep 整理(练习)

三剑客配合正则,从学习到使用,到熟练使用,再到得心应手,需要经过大量的练习沉淀,所以笔者准备了一些小练习,供大家进阶。

1. 概述

1.1 三剑客功能对比

三剑客通用功能独有功能
grep/egrep过滤过滤快,取反(也算删除)
sed过滤替换,修改文件内容,增加,删除,取行
awk过滤取列(取行),精确过滤(某一列包含),统计计算

1.2 正则

基础正则,扩展正则,通配符,linux中的特殊符号,笔者总是搞混,这里按使用类型简单做了整理

  • 表示重复(连续出现)
符号说明所属
+1次及以上,一般和[]一起使用扩展
*0次及以上,一般和.一起使用基础
?0次或1次扩展
{n,m}{n,m}连续出现多次,大于n,小于m次基础
  • 表示或者
符号说明所属
[a,b]等于a或者b基础
[a-b]等于a到b之间的某个字符基础
[^a-b]除了a到b之间的某个字符基础
  • 其他字符
符号说明所属
. 任意字符,默认一定有一个字符基础
.*任意长度字符,但不一定有字符基础
^一般用来匹配行首,如果在[^]则表示排除中括号中的内容基础
$一般用来匹配行尾基础
^$一般用来匹配空行基础
()在sed中用来反向引用,在扩展正则中表示群组扩展

详细参考 https://blog.csdn.net/u010230019/article/details/138622110

2. sed 回顾

这里引入sed的各种空间各自模式,避免走火入魔,有兴趣可以看看
SECTION 25 sed进阶(一)
SECTION 25 sed进阶(二)

我们准备一个练习文件,用于使用

[root@node-252 exercises]# cp /etc/passwd .
[root@node-252 exercises]# head -3 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

2.1 查找(过滤)

一般格式:

sed -n '[定位]p' filename

-n:取消默认输出
pprint打印匹配内容

  • 查找第2行
[root@node-252 exercises]# sed -n  '2p' passwd
bin:x:1:1:bin:/bin:/sbin/nologin
  • 查找第2到5行
[root@node-252 exercises]# sed -n  '2,5p' passwd
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

包括第5行哦

[root@node-252 exercises]# cat -n passwd
     1  root:x:0:0:root:/root:/bin/bash
     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
  • 查找匹配ntp的行
[root@node-252 exercises]# sed -n '/ntp/p' passwd
ntp:x:38:38::/etc/ntp:/sbin/nologin
  • 查找匹配ftpntp的行
[root@node-252 exercises]# sed -n '/ftp/,/ntp/p' passwd
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
ntp:x:38:38::/etc/ntp:/sbin/nologin
  • 查找包含ftpntp的行
[root@node-252 exercises]# sed -rn '/ftp|ntp/p' passwd
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin

这里需要使用-r选项,能够让sed支持扩展正则,|是扩展正则的符号

  • 查找包含大写字母的行
[root@node-252 exercises]# sed -rn '/[[:upper:]]/p' passwd
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
nginx:x:997:995:Nginx web server:/var/lib/nginx:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
gluster:x:996:992:GlusterFS daemons:/run/gluster:/sbin/nologin
unbound:x:994:990:Unbound DNS resolver:/etc/unbound:/sbin/nologin
saslauth:x:993:76:Saslauthd user:/run/saslauthd:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
saned:x:992:988:SANE scanner daemon user:/usr/share/sane:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
colord:x:990:984:User for colord:/var/lib/colord:/sbin/nologin
geoclue:x:989:983:User for geoclue:/var/lib/geoclue:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
sssd:x:988:982:User for sssd:/:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
  • 查找包含daemon的行,不区分大小写
[root@node-252 exercises]# sed -n '/daemon/Ip' passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
gluster:x:996:992:GlusterFS daemons:/run/gluster:/sbin/nologin
libstoragemgmt:x:995:991:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
saned:x:992:988:SANE scanner daemon user:/usr/share/sane:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin

I能够在匹配的时候忽略大小写

2.2 替换

一般格式:

sed -n 's#匹配内容#替换内容#gp' filename
#s/regexp/replacement/

我们使用#@$等特殊符号替换//,避免在使用中转义,毕竟特殊符号出现的频率比/低一些

  • 查找nginx,替换为apache
[root@node-252 exercises]# sed -n '/nginx/p' passwd
nginx:x:997:995:Nginx web server:/var/lib/nginx:/sbin/nologin
[root@node-252 exercises]# sed -n 's#nginx#apache#gp' passwd
apache:x:997:995:Nginx web server:/var/lib/apache:/sbin/nologin
  • 替换内容到文件
[root@node-252 exercises]# sed -i 's#nginx#apache#g' passwd
[root@node-252 exercises]# grep 'apache'  passwd
apache:x:997:995:Nginx web server:/var/lib/apache:/sbin/nologin

这个过程不会有任何提示,所以使用需谨慎

一个错误示例,仅把匹配内容写到了文件

[root@node-252 exercises]# sed -i -n 's#nginx#apache#gp' passwd
[root@node-252 exercises]# cat passwd
apache:x:997:995:Nginx web server:/var/lib/apache:/sbin/nologin

所以,禁止-n-i同时使用

  • 替换内容到文件,并把原文件备份
[root@node-252 exercises]# sed -i.bak 's#apache#nginx#g' passwd
[root@node-252 exercises]# diff passwd passwd.bak
21c21
< nginx:x:997:995:Nginx web server:/var/lib/nginx:/sbin/nologin
---
> apache:x:997:995:Nginx web server:/var/lib/apache:/sbin/nologin

这里-i后面可以加任何内容,当做备份文件的后缀名。但比较常用的例如.bak,.backup,见名知意。

2.3 反向引用

一般格式:

sed -r 's#(.*)#\1#g'

因为()属于扩展正则内容,所以想使用反向引用,那必须制定选项-r

  • 找到nancy的命令解释器
[root@node-252 exercises]# sed -rn 's#^nancy.*:(.*)$#\1#gp' passwd
/bin/bash
  • 使用sed找到本机ens33网卡的ip
[root@node-252 exercises]# ip a s ens33|sed -rn 's#.*inet (.*)/24.*#\1#gp'
192.168.202.128

我们一定要能定位到引用内容的位置,并用(.*)表示

  • 把匹配内容用<>括起来
[root@node-252 exercises]# echo 123456|sed -r 's#(.*)#<&>#g'
<123456>

如果匹配的是所有内容,可以使用&表示前面所有的匹配内容

2.4 删除

一般格式:

sed '[定位]d' filename

只要不加-i就不会修改文件

  • 删除第1行
[root@node-252 exercises]# sed '1d' passwd|head -2
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
  • 删除第1到3行
[root@node-252 exercises]# sed '1,3d' passwd|head -2
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  • 删除包含rootadm的行
[root@node-252 exercises]# sed -r '/root|adm/d' passwd|head -2
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
  • 删除包含rootadm的行
[root@node-252 exercises]# sed -r '/root/,/adm/d' passwd|head -2
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync

这部分和查找的使用方式基本类似

2.5 增加

一般格式:

sed '[定位]a' filename	#append 追加
sed '[定位]i' filename	#insert 插入
sed '[定位]c' filename   #replace 替换

这里的替换,c和前面的s区别在于,c替换整行内容,s替换匹配内容

  • 在第二行追加,插入,替换hello sed
[root@node-252 exercises]# sed '2a hello sed' passwd|head -3
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
hello sed
[root@node-252 exercises]# sed '2i hello sed' passwd|head -3
root:x:0:0:root:/root:/bin/bash
hello sed
bin:x:1:1:bin:/bin:/sbin/nologin
[root@node-252 exercises]# sed '2c hello sed' passwd|head -3
root:x:0:0:root:/root:/bin/bash
hello sed
daemon:x:2:2:daemon:/sbin:/sbin/nologin
  • root所在行追加,插入,替换为hello sed
[root@node-252 exercises]# sed '/root/a hello sed' passwd|head -3
root:x:0:0:root:/root:/bin/bash
hello sed
bin:x:1:1:bin:/bin:/sbin/nologin
[root@node-252 exercises]# sed '/root/i hello sed' passwd|head -3
hello sed
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@node-252 exercises]# sed '/root/c hello sed' passwd|head -3
hello sed
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
  • rootadm行替换为hello sed
[root@node-252 exercises]# sed '/root/,/adm/c hello sed' passwd|head -3
hello sed
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync

以上是sed的简单回顾,sed的强项是对行进行操作

3. awk 回顾

先记个通用格式吧

awk [options] '条件类型1 {动作1} [ 条件类型2 {动作2} ] ...' filename

3.1 取行

  • 查找第一行
[root@node-252 exercises]# awk 'NR==1{print}' passwd
root:x:0:0:root:/root:/bin/bash
[root@node-252 exercises]# awk 'NR==1' passwd
root:x:0:0:root:/root:/bin/bash

printawk的默认动作,会把匹配的内容进行打印,可以不写,但不能写的不完整,例如NR==1{}NR==1 print都是不可以的

  • 查找包含rootadm的行
[root@node-252 exercises]# awk '/root|adm/' passwd
root:x:0:0:root:/root:/bin/bash
adm:x:3:4:adm:/var/adm:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

awk默认支持扩展正则

  • 查找第2到5行内容
[root@node-252 exercises]# awk 'NR>=2 && NR<=5' passwd
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@node-252 exercises]# awk 'NR==2,NR==5' passwd
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

,逗号在定位的时候基本上表示范围

  • 查找第2和第5行内容
[root@node-252 exercises]# awk 'NR==2 || NR==5' passwd
bin:x:1:1:bin:/bin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@node-252 exercises]# awk 'NR==2;NR==5' passwd
bin:x:1:1:bin:/bin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  • 查找除了第1行的内容
[root@node-252 exercises]# awk '!(NR==1)' passwd |head -2
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

awk取行的关键字NR(Number of Records)

3.2 取列

为了观看方便,我们把passwd只保留前5行

[root@node-252 exercises]# sed -i '6,$ d' passwd
[root@node-252 exercises]# cat 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
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  • 查找用户名和对应的UID
[root@node-252 exercises]# awk -F: '{print $1,$3}' passwd|column -t
root    0
bin     1
daemon  2
adm     3
lp      4
[root@node-252 exercises]# awk 'FS=":"{print $1,$3}' passwd
root:x:0:0:root:/root:/bin/bash
bin 1
daemon 2
adm 3
lp 4

-FFS都可以指定分隔符

‌awk的FS设置如果不在BEGIN{}中设置,会导致第一行处理不正确。‌这是因为awk在处理文件时,如果需要在BEGIN{}之外设置FS(字段分隔符),则默认会认为是在寻找特定的模式(/pattern/),而没有对应的action(操作),因此会默认打印整行,导致第一行处理错误。为了正确设置FS或在awk脚本中执行其他需要在文件开始前设置的变量或操作,应该使用BEGIN{}来初始化这些变量。此外,如果想要跳过文件的第一行,可以使用条件NR>1来实现,其中NR表示当前处理的行号。这样,awk将处理从第二行开始的行,从而避免处理第一行时可能出现的错误‌

所以如果使用FS应该在BEGIN模块指定

[root@node-252 exercises]# awk 'BEGIN{FS=":"} {print $1,$3}' passwd
root 0
bin 1
daemon 2
adm 3
lp 4
  • 取出内容并加上行号
[root@node-252 exercises]# awk -F: '{print NR,$0}' passwd
1 root:x:0:0:root:/root:/bin/bash
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
[root@node-252 exercises]# cat -n passwd
     1  root:x:0:0:root:/root:/bin/bash
     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
[root@node-252 exercises]# nl passwd
     1  root:x:0:0:root:/root:/bin/bash
     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
  • 取出每行,并显示有多少列
[root@node-252 exercises]# awk -F: '{print $1,$3,NF}' passwd |column -t
root    0  7
bin     1  7
daemon  2  7
adm     3  7
lp      4  7
[root@node-252 exercises]# awk -F: '{print $1,$3,$NF}' passwd |column -t
root    0  /bin/bash
bin     1  /sbin/nologin
daemon  2  /sbin/nologin
adm     3  /sbin/nologin
lp      4  /sbin/nologin

awk中的内置变量,在引用的时候,不需要加$,否则会有歧义

  • 取出UID以1,2开始的行
[root@node-252 exercises]# awk -F: '$3~/^[12]/' passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

$3~/***/~波浪线代表包含的以上

  • 取出UID不以1,2开始的行
[root@node-252 exercises]# awk -F: '$3!~/^[12]/' passwd
root:x:0:0:root:/root:/bin/bash
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  • 取出UID以1,2结尾的行
[root@node-252 exercises]# awk -F: '$3~/[12]$/' passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
  • 取出UID以1,2结尾的行的第1,3列
[root@node-252 exercises]# awk -F: '$3~/[12]$/ {print $1,$3}' passwd
bin 1
daemon 2

awk可以换一种思考方式:

条件 => 取行
动作 => 取列

上面的例子中:
条件$3~/[12]$/取行

bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

动作print $1,$3取列

bin 1
daemon 2

3.3 BEGIN

执行顺序简述:
1. BEGIN{}	: 最开始执行,读取文件之前
2. //		: 正则
3. {}		: 循环体
4. END{}	: 最后执行,读完文件之后

记住BEGIN是在读取文件前执行的操作,在BEGIN中可以进行一些和文件内容无关的操作,比如定义分隔符,做一些运算等

‌AWK的BEGIN块主要用于在处理任何输入之前执行初始化操作,包括变量初始化、打印表头信息等。‌ 在BEGIN块中,你可以执行各种计算和初始化操作,为后续的数据处理做好准备。例如,你可以在BEGIN块中设置初始值、定义变量,或者进行一些预处理计算。
BEGIN块的使用非常灵活,可以用于执行各种任务,包括但不限于:

  • 初始化变量:在处理任何输入数据之前,你可以在BEGIN块中定义和初始化变量,这些变量可以在后续的代码中使用。例如,你可以设置一个总和变量为0,以便在处理数据时累加数值。
  • 打印表头:如果你需要在输出中包含表头信息,可以在BEGIN块中打印这些信息。
  • 执行预处理计算:在BEGIN块中,你还可以执行一些预处理计算,这些计算结果可以在后续的数据处理中使用。

通过使用BEGIN块,你可以确保在处理任何输入数据之前完成必要的初始化和准备工作,从而使你的AWK脚本更加健壮和可靠。此外,BEGIN块的执行是在处理任何输入数据之前,因此它提供了一个理想的位置来进行全局的设置和初始化操作‌

  • 计算1/3,1+3
[root@node-252 exercises]# awk 'BEGIN{print 1/3,1+3}'
0.333333 4

可以看到awk中的BEGIN模块支持计算,并且是浮点计算,这个功能要比exprbc方便一些

  • 找出UID小于3的账号
[root@node-252 exercises]# awk -F: 'BEGIN{min=3} $3<min {print $1,$3}' passwd
root 0
bin 1
daemon 2

需要注意在BEGIN中定义的变量,在引用的时候不需要加$,有点类似内置变量

  • 找出本机中的非系统用户
[root@node-252 exercises]# awk -F: 'BEGIN{sys=999} $3>sys{print $1,$3}' /etc/passwd
nfsnobody 65534
yurq 1000
jacky 1001
nancy 1002

不同系统中的非系统用户的UID取值范围可能不同,参考/etc/login.defs

  • 定义变量
[root@node-252 exercises]# awk 'BEGIN{FS=":"} {print $1,$3}' passwd
root 0
bin 1
daemon 2
adm 3
lp 4

3.4 END

END在读取文件之后执行,所以可以进行一些统计工作

  • 获得文件行数
[root@node-252 exercises]# awk -F: '{i++} END{print i}' passwd
5
[root@node-252 exercises]# awk -F: 'BEGIN{i=0} {i++} END{print i}' passwd
5

这里的i如果未初始化,默认为0awk读取每行文件,进行i++计算,读取文件结束后,在END模块进行打印

  • 统计可登录用户数量
[root@node-252 exercises]# awk -F: '/bash$/{i++} END{print i}' /etc/passwd
4
[root@node-252 exercises]# grep 'bash' /etc/passwd
root:x:0:0:root:/root:/bin/bash
yurq:x:1000:1000:yurq:/home/yurq:/bin/bash
jacky:x:1001:1003::/home/jacky:/bin/bash
nancy:x:1002:1003::/home/nancy:/bin/bash
[root@node-252 exercises]# awk -F: '/bash$/{i++;print $1} END{print i}' /etc/passwd
root
yurq
jacky
nancy
4

命令解释器为bash的用户认为是可登录用户,多个动作之间用;分号隔离

  • 统计/etc/services中的空行总数
[root@node-252 exercises]# awk '/^$/{c++;print c;print $0} END{print "total:" c}' /etc/services
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

total:17

当然,打印非空行

awk '!/^$/{c++;print c;print $0} END{print "total:" c}' /etc/services
  • 假设/etc/passwd中的UID为流量,并且单位是MB,统计一共用了多少GB流量
[root@node-252 exercises]# awk -F: '{sum+=$3} END{print sum/1024 "GB"}' /etc/passwd
81.2568GB

3.5 gsub(替换功能)

gsubawk中的一个内置函数,用于全局替换
一般格式:

gsub(regex, replacement, target)
  • root替换成toor
[root@node-252 exercises]# awk 'gsub(/root/,"toor")' passwd
toor:x:0:0:toor:/toor:/bin/bash

精确到列

[root@node-252 exercises]# awk -F: 'gsub(/root/,"toor",$1)' passwd
toor x 0 0 root /root /bin/bash
  • passwd中的数字删除
[root@node-252 exercises]# awk 'gsub(/[[:digit:]]/,"")' passwd
root:x:::root:/root:/bin/bash
bin:x:::bin:/bin:/sbin/nologin
daemon:x:::daemon:/sbin:/sbin/nologin
adm:x:::adm:/var/adm:/sbin/nologin
lp:x:::lp:/var/spool/lpd:/sbin/nologin

gsub虽然能实现一些简单的替换功能,但是相较于sed可能还是略显不足

4. 练习

正式练习现在才刚刚开始~~

以下示例以/etc/passwd为练习文件,建议拷贝到其他目录进行使用。本文中的passwd进行精简,节省篇幅

[root@node-252 exercises]# cat 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
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  1. 删除所有数字
[root@node-252 exercises]# sed -r 's#[[:digit:]]+##g' passwd
root:x:::root:/root:/bin/bash
bin:x:::bin:/bin:/sbin/nologin
daemon:x:::daemon:/sbin:/sbin/nologin
adm:x:::adm:/var/adm:/sbin/nologin
lp:x:::lp:/var/spool/lpd:/sbin/nologin
[root@node-252 exercises]# sed -r 's#[0-9]+##g' passwd
root:x:::root:/root:/bin/bash
bin:x:::bin:/bin:/sbin/nologin
daemon:x:::daemon:/sbin:/sbin/nologin
adm:x:::adm:/var/adm:/sbin/nologin
lp:x:::lp:/var/spool/lpd:/sbin/nologin

  1. 删除每行开头空格
[root@node-252 exercises]# cat >> test <<eof
>   123
>  456
>       789;
> ==
>                   200
> eof
[root@node-252 exercises]# cat -A test
  123$
 456$
      789;$
==$
                  200$
[root@node-252 exercises]# sed -r 's#^ +##g' test
123
456
789;
==
200
  1. 用制表符替换空格
[root@node-252 exercises]# sed -r 's#^ +#\t#g' test
        123
        456
        789;
==
        200
  1. 所有数字用{}括起来
[root@node-252 exercises]# sed -r 's#([0-9]+)#{\1}#g' 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
adm:x:{3}:{4}:adm:/var/adm:/sbin/nologin
lp:x:{4}:{7}:lp:/var/spool/lpd:/sbin/nologin
[root@node-252 exercises]# sed -r 's#([0-9]+)#{&}#g' 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
adm:x:{3}:{4}:adm:/var/adm:/sbin/nologin
lp:x:{4}:{7}:lp:/var/spool/lpd:/sbin/nologin
  1. 删除文件中第一个字符
[root@node-252 exercises]# sed 's#^.##g' passwd
oot:x:0:0:root:/root:/bin/bash
in:x:1:1:bin:/bin:/sbin/nologin
aemon:x:2:2:daemon:/sbin:/sbin/nologin
dm:x:3:4:adm:/var/adm:/sbin/nologin
p:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@node-252 exercises]# awk 'gsub(/^./,"")' passwd
oot:x:0:0:root:/root:/bin/bash
in:x:1:1:bin:/bin:/sbin/nologin
aemon:x:2:2:daemon:/sbin:/sbin/nologin
dm:x:3:4:adm:/var/adm:/sbin/nologin
p:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  1. 删除第二个字符
[root@node-252 exercises]# sed -r 's#(.).(.*)#\1\2#g' passwd
rot:x:0:0:root:/root:/bin/bash
bn:x:1:1:bin:/bin:/sbin/nologin
demon:x:2:2:daemon:/sbin:/sbin/nologin
am:x:3:4:adm:/var/adm:/sbin/nologin
l:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@node-252 exercises]# sed -r 's#^(.).#\1#g' passwd
rot:x:0:0:root:/root:/bin/bash
bn:x:1:1:bin:/bin:/sbin/nologin
demon:x:2:2:daemon:/sbin:/sbin/nologin
am:x:3:4:adm:/var/adm:/sbin/nologin
l:x:4:7:lp:/var/spool/lpd:/sbin/nologin

了解

[root@node-252 exercises]# awk '{print gensub(/^(.)./,"\\1","g")}' passwd
rot:x:0:0:root:/root:/bin/bash
bn:x:1:1:bin:/bin:/sbin/nologin
demon:x:2:2:daemon:/sbin:/sbin/nologin
am:x:3:4:adm:/var/adm:/sbin/nologin
l:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  1. 删除最后一个字符
[root@node-252 exercises]# sed 's#.$##g' passwd
root:x:0:0:root:/root:/bin/bas
bin:x:1:1:bin:/bin:/sbin/nologi
daemon:x:2:2:daemon:/sbin:/sbin/nologi
adm:x:3:4:adm:/var/adm:/sbin/nologi
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologi
  1. 删除倒数第二个字符
[root@node-252 exercises]# sed -r 's#.(.)$#\1#g' passwd
root:x:0:0:root:/root:/bin/bah
bin:x:1:1:bin:/bin:/sbin/nologn
daemon:x:2:2:daemon:/sbin:/sbin/nologn
adm:x:3:4:adm:/var/adm:/sbin/nologn
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologn
  1. 删除第二个单词

这里我们认为连续的字母组成的字符串就是单词,此例中可以认为是x,但想表达的不是仅仅删x

#这里我们知道文件内容格式,所以这样写
[root@node-252 exercises]# sed -r 's#^([[:alpha:]]+:)[[:alpha:]]+#\1#g' passwd
root::0:0:root:/root:/bin/bash
bin::1:1:bin:/bin:/sbin/nologin
daemon::2:2:daemon:/sbin:/sbin/nologin
adm::3:4:adm:/var/adm:/sbin/nologin
lp::4:7:lp:/var/spool/lpd:/sbin/nologin
[root@node-252 exercises]# sed -r 's#(^[^:]+:)[^:]+#\1#g' passwd
root::0:0:root:/root:/bin/bash
bin::1:1:bin:/bin:/sbin/nologin
daemon::2:2:daemon:/sbin:/sbin/nologin
adm::3:4:adm:/var/adm:/sbin/nologin
lp::4:7:lp:/var/spool/lpd:/sbin/nologin
[root@node-252 exercises]# sed -r 's#(^[^:]+:).#\1#g' passwd		#玩赖写法
root::0:0:root:/root:/bin/bash
bin::1:1:bin:/bin:/sbin/nologin
daemon::2:2:daemon:/sbin:/sbin/nologin
adm::3:4:adm:/var/adm:/sbin/nologin
lp::4:7:lp:/var/spool/lpd:/sbin/nologin

通用的删除第二个单词

[root@node-252 exercises]# head -10 /etc/services
# /etc/services:
# $Id: services,v 1.55 2013/04/14 ovasik Exp $
#
# Network services, Internet style
# IANA services version: last updated 2013-04-10
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, most entries here have two entries
# even if the protocol doesn't support UDP operations.
# Updated from RFC 1700, ``Assigned Numbers'' (October 1994).  Not all ports
[root@node-252 exercises]# head -10 /etc/services|sed -r 's#([^[:alpha:]]*)([[:alpha:]]+)([^[:alpha:]]+)([[:alpha:]]+)#\1\2\3#g'
# /etc/:
# $Id: ,v 1.55 2013/04/14  Exp $
#
# Network , Internet
# IANA  version:  updated 2013-04-10
#
# Note  it  presently  policy  IANA  assign  single -known
# port  for  TCP  UDP; , most  here  two
# even  the  doesn' support  operations.
# Updated  RFC 1700, `` Numbers'' ( 1994).  Not  ports

  1. 删除倒数第二个单词
#删除倒数第二段字符串
[root@node-252 exercises]# sed -r 's#[a-Z/]+:([a-Z/]+)$#\1#g' passwd
root:x:0:0:root:/bin/bash
bin:x:1:1:bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin/nologin
adm:x:3:4:adm:/sbin/nologin
lp:x:4:7:lp:/sbin/nologin

通用

[root@node-252 exercises]# sed -r 's#[[:alpha:]]+([^[:alpha:]]*)([[:alpha:]]+)([^[:alpha:]]*)$#\1\2\3#g' passwd
root:x:0:0:root:/root://bash
bin:x:1:1:bin:/bin://nologin
daemon:x:2:2:daemon:/sbin://nologin
adm:x:3:4:adm:/var/adm://nologin
lp:x:4:7:lp:/var/spool/lpd://nologin
  1. 删除最后一个单词
[root@node-252 exercises]# sed -r 's#[a-Z]+$##g' passwd
root:x:0:0:root:/root:/bin/
bin:x:1:1:bin:/bin:/sbin/
daemon:x:2:2:daemon:/sbin:/sbin/
adm:x:3:4:adm:/var/adm:/sbin/
lp:x:4:7:lp:/var/spool/lpd:/sbin/
  1. 交换每行第一个和第二个字符
[root@node-252 exercises]# sed -r 's#^(.)(.)#\2\1#g' passwd
orot:x:0:0:root:/root:/bin/bash
ibn:x:1:1:bin:/bin:/sbin/nologin
ademon:x:2:2:daemon:/sbin:/sbin/nologin
dam:x:3:4:adm:/var/adm:/sbin/nologin
pl:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  1. 交换第一个字符和第二个单词
[root@node-252 exercises]# sed -r 's#^(.)([[:alpha:]]*)([^[:alpha:]]+)([[:alpha:]]+)#\4\2\3\1#g' passwd
xoot:r:0:0:root:/root:/bin/bash
xin:b:1:1:bin:/bin:/sbin/nologin
xaemon:d:2:2:daemon:/sbin:/sbin/nologin
xdm:a:3:4:adm:/var/adm:/sbin/nologin
xp:l:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@node-252 exercises]# sed -r 's#^(.)([a-Z]+:)([a-Z]+)#\3\2\1#g' passwd
xoot:r:0:0:root:/root:/bin/bash
xin:b:1:1:bin:/bin:/sbin/nologin
xaemon:d:2:2:daemon:/sbin:/sbin/nologin
xdm:a:3:4:adm:/var/adm:/sbin/nologin
xp:l:4:7:lp:/var/spool/lpd:/sbin/nologin


[root@node-252 exercises]# head -10 /etc/services|sed -r 's#^(.)([[:alpha:]]*)([^[:alpha:]]+)([[:alpha:]]+)([^[:alpha:]]+)([[:alpha:]]+)#\6\2\3\4\5\1#g'
services /etc/#:
services $Id: #,v 1.55 2013/04/14 ovasik Exp $
#
services Network #, Internet style
services IANA # version: last updated 2013-04-10
#
that Note # it is presently the policy of IANA to assign a single well-known
number port # for both TCP and UDP; hence, most entries here have two entries
if even # the protocol doesn't support UDP operations.
from Updated # RFC 1700, ``Assigned Numbers'' (October 1994).  Not all ports
[root@node-252 exercises]# head -10 /etc/services
# /etc/services:
# $Id: services,v 1.55 2013/04/14 ovasik Exp $
#
# Network services, Internet style
# IANA services version: last updated 2013-04-10
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, most entries here have two entries
# even if the protocol doesn't support UDP operations.
# Updated from RFC 1700, ``Assigned Numbers'' (October 1994).  Not all ports
  1. 交换第一个单词和最后一个单词
[root@node-252 exercises]# sed -r 's#^([[:alpha:]]+)(.*/)([[:alpha:]]+)$#\3\2\1#g' passwd
bash:x:0:0:root:/root:/bin/root
nologin:x:1:1:bin:/bin:/sbin/bin
nologin:x:2:2:daemon:/sbin:/sbin/daemon
nologin:x:3:4:adm:/var/adm:/sbin/adm
nologin:x:4:7:lp:/var/spool/lpd:/sbin/lp
  1. 每行打印3次
[root@node-252 exercises]# sed 'p;p' passwd
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

默认打印一次,每多加个p多打印一次

  1. 隔行删除
[root@node-252 exercises]# seq 10|sed '1~2d'
2
4
6
8
10
[root@node-252 exercises]# seq 10|sed '2~2d'
1
3
5
7
9
[root@node-252 exercises]# seq 10|sed -n '1~2p'
1
3
5
7
9
  1. 仅显示第一列
[root@node-252 exercises]# grep -E -o '^[a-Z]+' passwd
root
bin
daemon
adm
lp
[root@node-252 exercises]# awk -F: '{print $1}' passwd
root
bin
daemon
adm
lp
[root@node-252 exercises]# sed -r 's#^([[:alpha:]]+).*#\1#g' passwd
root
bin
daemon
adm
lp

可以看出awk处理列内容更便捷

本次就这些 ^_^

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值