文本处理工具

这里写目录标题

  • 文本处理工具
    • 一.正则表达式
      • 1.元字符
      • 2.表示次数
      • 3.位置锚定
      • 4.分组或其他
    • 二.grep
    • 三.AWK
    • 三.sed

文本处理工具

一.正则表达式

主要用来匹配字符串(命令结果,文本内容)**,

通配符匹配文件(而且是已存在的文件)

  • 基本正则表达式

  • 扩展正则表达式

1.元字符

.   匹配任意单个字符,可以是一个汉字  
[]   匹配指定范围内的任意单个字符,示例:[qwer]   [0-9]   []   [a-zA-Z]   [:alpha:]
[^] 匹配指定范围外的任意单个字符,示例:[^qwer] [^a.z] [a.z]


[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]包含的范围
广
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
\w #匹配单词构成部分,等价于[_[:alnum:]]
\W #匹配非单词构成部分,等价于[^_[:alnum:]]
\S     #匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\s     #匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意
Unicode 正则表达式会匹配全角空格符
[root@localhost opt]#ls /etc/|grep rc[.0-6]
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local

[root@localhost opt]#grep r..t /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
//r..t ..代表任意两个字符

[root@localhost ~]# echo abc |grep a.c              
//表示原来的点需要加\转义
abc
[root@localhost ~]# echo abc |grep a\.c
//不加引号有时匹配会有出入
abc
[root@localhost ~]# echo abc |grep 'a\.c'          
//标准格式需要加'' 或者""

[root@localhost ~]# ls [a-d].txt                
//通配符
a.txt  A.txt  b.txt  B.txt  c.txt  C.txt  d.txt
[root@localhost ~]# ls |grep '[a-d].txt'             
//真正的小写在正则表达式中
a.txt
b.txt
c.txt
d.txt

2.表示次数

*    匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.*   任意长度的任意字符,不包括0次
\?   匹配其前面的字符出现0次或1次,即:可有可无
\+   匹配其前面的字符出现最少1次,即:肯定有且 >=1 次
\{n\}匹配前面的字符n次
\{m,n\} 匹配前面的字符至少m次,至多n次
\{,n\}  匹配前面的字符至多n次,<=n
\{n,\}  匹配前面的字符至少n次
[root@localhost opt]#echo google |grep 'go\{2\}gle'
google
[root@localhost opt]#echo gooogle |grep 'go\{2\}gle'
[root@localhost opt]#
//表示指定o出现2次

[root@localhost opt]#echo gooooogle |grep 'go\{2,5\}gle'
gooooogle
[root@localhost opt]#echo gooooooogle |grep 'go\{2,5\}gle'
[root@localhost opt]#
//指定o出现2次及以上,5次及以下

[root@localhost opt]#echo google |grep "go\+gle"
google

3.位置锚定

^ 行首锚定, 用于模式的最左侧
$ 行尾锚定,用于模式的最右侧
^PATTERN$ 用于模式匹配整行 (单独一行  只有root)
^$ 空行
^[[:space:]]*$   空白行


\< 或 \b       词首锚定,用于单词模式的左侧(连续的数字,字母,下划线都算单词内部)
\> 或 \b       词尾锚定,用于单词模式的右侧
\    匹配整个单词
过滤出不是以#号开头的非空行
[root@localhost opt]#grep "^[^#]" /etc/fstab
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=e45c4df7-fe8f-41e0-ab99-5f16e1968a8f /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0


//[^#]表示不是#的字符,^[^#]表示不以#开头

4.分组或其他

分组:() 将多个字符捆绑在一起,当作一个整体处理,如:(root)+

或者
或者:\ |

[root@localhost ~]#echo abccc |grep "abc\{3\}"
abccc

[root@localhost ~]#echo abcabcabc |grep "\(abc\)\{3\}"
//分组 匹配abc
abcabcabc
[root@localhost ~]#echo 1abc |grep  "1\|2abc"
//只匹配了1
1abc

[root@localhost ~]#echo 1abc |grep  "\(1\|2\)abc"
//1abc或者2abc
1abc

[root@localhost ~]#ifconfig ens33|grep netmask|grep -o '\([0-9]\{1,3\}\.\)\{3\}[0-9]\{3\}'|head -1
192.168.82.100

5.扩展正则表达式

grep -E

egrep

表示次数

*   匹配前面字符任意次
? 0或1次
+ 1次或多次
{n} 匹配n次
{m,n} 至少m,至多n次
{,n}  匹配前面的字符至多n次,<=n,n可以为0
{n,} 匹配前面的字符至少n次,<=n,n可以为0

表示分组

() 分组
分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
后向引用:\1, \2, ...
| 或者  
a|b a或b
C|cat C或cat
(C|c)at Cat或cat
[root@localhost ~] ens33 |grep netmask|grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'|head -1
echo "13705173391"|grep -E "\b1[3456789][0-9]{9}\b"
//表示手机号
echo "[email protected]" |grep -E "[[:alnum:]_]+@[[:alnum:]_]+\.[[:alnum:]_]+"
//表示手机号

二.grep

grep [选项]… 查找条件 文件

-m //匹配m次后停止
[root@localhost opt]#cat /etc/passwd | grep -m 1 root
root:x:0:0:root:/root:/bin/bash
//只显示一行

-v  //显示不被pattern匹配到的行,即取反
[root@localhost opt]#cat /etc/passwd | grep -m 5 -v root
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
//只显示了5行没有root的记录

-i //忽略大小写
-n //显示行号
-c //统计行数
[root@localhost opt]#cat /etc/passwd | grep -c root
2
[root@localhost opt]#cat /etc/passwd | grep -n root
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin


-o //只显示匹配到的字符串
-q //不输出信息,静默模式
-A //后x行
-B //前x行
-C //前后各x行
[root@localhost opt]#cat /etc/passwd | grep -o root
root
root
root
root
//只显示字符串
[root@localhost opt]#cat /etc/passwd | grep -A 5 root
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
--
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
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
//因为有两行root的匹配行,所以分别显示了各自的后5行

-e //实现多个选项间的逻辑关系or
[root@localhost opt]#cat /etc/passwd | grep -e root -e bash
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
test:x:1000:1000:test:/home/test:/bin/bash
//包含root或者包含bash 的行

-w //匹配整个单词
-f file //根据模式文件,处理两个文件相同内容 把第一个文件作为匹配条件
-r   //递归目录,但不处理软链接
-R   //递归目录,但处理软链接

三.AWK

awk 比较倾向于将一行分成多个“字段”然后再进行处理,且默认情况下字段的分隔符为空格或 tab 键。awk 执行结果可以通过 print 的功能将字段数据打印显示。

awk  [options]  'program' var=value file..

awk  选项  模式  处理动作
          指定   '{print  }'

-F  指定分隔符
-v  自定义变量
-f  脚本

awk [options]  -f programfile  var=value file..

program通常是被放在单引号中,并可以由三种部分组成
BEGIN语句块
模式匹配的通用语句块
END语句块

pattern{action statements;..}
pattern:决定动作语句何时触发及触发事件,比如:BEGIN,END,正则表达式等
action statements:对数据进行处理,放在{}内指明,常见:print, printf

常见选项:
-F “分隔符” 指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符
-v var=value  变量赋值

awk [选项] '模式条件{操作}' 文件1 文件2 ....

awk -f|-v 脚本文件 文件1 文件2.....
[root@yyds opt]#awk '{print "hello"}'
1
hello
2
hello
3
hello
4
hello
//字符串需要添加双引号,单引号已被使用

[root@yyds opt]#ls | awk '{print "hello"}'
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
//以每个文件作为标准输入,任何执行print "hello"
[root@yyds opt]#awk '{print "hello"}' < /etc/passwd
hello
....
//以文件里面每行作为一个标准输入导给awk,执行处理动作

[root@yyds opt]#awk 'BEGIN{print 100+200}' 
300
//语句块执行运算

[root@yyds opt]#awk -F: 'BEGIN {print "hello"} {print $1}' /etc/passwd |head -n3
hello
root
bin
//先处理BEGIN中的动作,在处理普通的语句块中动作,再显示前三行得到
END反之,注意tail和head的使用

[root@yyds opt]#df|awk '{print $5}'|awk -F% '{print $1}'|tail -n +2
11
0
0
1
0
4
1
0
//awk默认以空格或者连续的空格为分隔符,-F可以指定分隔符

[root@yyds opt]#cat /etc/passwd|awk -F: '{print $1":"$3}'
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
games:12
ftp:14
......
//指定:为分隔符,并且过滤出1,3列,并以:为分隔符输出

[root@yyds opt]#ifconfig ens33|grep netmask|awk '{print $2}'
192.168.82.100
//提取ip地址,先过滤出ip地址所在行,再过滤出所在列
[root@yyds opt]#hostname -I|awk '{print $1}'
192.168.82.100

[root@yyds opt]#awk '/^root/{print}' /etc/passwd 
root:x:0:0:root:/root:/bin/bash
//过滤出以root开头的行
awk '/bash$/{print}' /etc/passwd 


awk 常见的内置变量

  • FS :指定每行文本的字段分隔符,缺省为空格或制表符(tab)。与 “-F”作用相同 -v “FS=:”
  • OFS:输出时的分隔符
  • NF:当前处理的行的字段个数
  • NR:当前处理的行的行号(序数)
  • $0:当前处理的行的整行内容
  • $n:当前处理行的第n个字段(第n列)
  • FILENAME:被处理的文件名
  • RS:行分隔符。awk从文件上读取资料时,将根据RS的定义就把资料切割成许多条记录,而awk一次仅读入一条记录进行处理。预设值是\n
[root@yyds opt]#awk -v FS=':' '{print $1FS$3}' /etc/passwd
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
....
//以:为分隔符,再以:为分隔符输出
awk -F: '{print $1":"$3}' /etc/passwd
fs=":";awk -v FS=$fs '{print $1FS$3}' /etc/passwd
//支持定义变量传给FS

fs=":";awk -v FS=$fs -v OFS="+" '{print $1,$3}' /etc/passwd
//OFS指定输出时的分隔符

[root@yyds opt]#awk -v RS=':' '{print $0}' /etc/passwd
root
x
0
0
root
/root
/bin/bash
......
//默认以/n(换行符)为一条记录的分隔符,这里指定:为记录分隔符,所以分行输出

[root@yyds opt]#awk -F: '{print NF}' /etc/passwd
7
7
7
7
7
7
//代表每行有7个字段
[root@yyds opt]#awk -F: '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
/sbin/shutdown
/sbin/halt
/sbin/nologin
/sbin/nologin
//$NF代表最后一个字段
[root@yyds opt]#df|awk -F "[ %]+" '{print $(NF-1)}'
已用
11
0
0
1
0
4
1
0

[root@yyds opt]#awk '{print $1,NR}' /etc/passwd
root:x:0:0:root:/root:/bin/bash 1
bin:x:1:1:bin:/bin:/sbin/nologin 2
daemon:x:2:2:daemon:/sbin:/sbin/nologin 3
adm:x:3:4:adm:/var/adm:/sbin/nologin 4
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 5
sync:x:5:0:sync:/sbin:/bin/sync 6
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 7
halt:x:7:0:halt:/sbin:/sbin/halt 8
//显示行号
[root@yyds opt]#awk 'NR==2{print $1}' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
//指定第几行
awk 'NR==1,NR==3{print}' /etc/passwd
//打印出1到3 行
awk 'NR==1||NR==3{print}' /etc/passwd
//打印出1和3行
awk '(NR%2)==0{print NR}' /etc/passwd
//打印出偶数行
awk '(NR%2)==1{print NR}' /etc/passwd
//打印出奇数行
awk 'NR>=3 && NR<=6{print NR,$0}' /etc/passwd
//打印出3到6行
awk 'NR>3 && NR<6{print NR,$0}' /etc/passwd
//打印出3到6行(不包括3,6行)
awk '$3>1000{print}' /etc/passwd
//打印出普通用户 第三列 大于1000 的行

[root@yyds opt]#awk '{print FNR}' /etc/issue /etc/os-release 
1
2
3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//与NR不同,FNR在读入一个新文件时会重新从第一行开始计数

[root@yyds opt]#awk -F: 'NR==2{print FILENAME}' /etc/passwd
/etc/passwd
//显示文件名

自定义变量

[root@yyds ~]#awk -v test='hello' 'BEGIN{print test}'
hello
[root@yyds ~]#awk -v test1=test2="hello" 'BEGIN{test1=test2="hello";print test1,test2}'
hello hello

模式

awk ‘模式{处理动作}’

不支持使用行号,但是可以使用变量NR 间接指定行号

gender
///正则表达式
/pat1/   
// 匹配pat1 的行

/pat1/,/pat2/ 
//正则表达式1   到正则表达式2  之间的行       如果匹配不到2的表达式  会一直匹配到文末

pat1   正则表达式1
pat2   正则表达式2

//模糊匹配,用~表示包含,!~表示不包含

比较操作符:
==, !=, >, >=, <, <=

逻辑
与:&&,并且关系
或:||,或者关系
非:!,取反

[root@yyds ~]#seq 10 |awk 'NR>=3 && NR<=6'
3
4
5
6
[root@yyds ~]#awk 'NR>=3 && NR<=6{print NR,$0}' /etc/passwd
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
6 sync:x:5:0:sync:/sbin:/bin/sync
[root@yyds ~]#awk -F:  '$3>=100 && $3<=1000{print $1}' /etc/passwd
systemd-network
polkitd
abrt
libstoragemgmt
colord
saslauth
setroubleshoot
rtkit
pulse
qemu
chrony
usbmuxd
geoclue
sssd
gnome-initial-setup
test
dhcpd

[root@yyds ~]#seq 10 | awk 'NR%2==0'
2
4
6
8
10
//取偶数行
[root@yyds ~]#seq 10 | awk 'NR%2==1'
1
3
5
7
9
//取奇数行或者awk 'NR%2!=0'

条件判断

if语句:awk的if语句也分为单分支、双分支和多分支
单分支为if(){}
双分支为if(){}else{}
多分支为if(){}else if(){}else{}

[root@yyds ~]#awk -F: '{if($3<1000)print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
.......

[root@yyds ~]#awk -F: '{if($3>1000){print $1,$3}else if($3<=1000){print $3}}' /etc/passwd
0
1
2
3
4
5
6
7
8
11
.....
test1 1001
test2 1002
test3 1003
test4 1004
test5test6 1005
//如果第三列数字大于1000,输出1.3列,如果小于等于1000,输出第三列

循环

[root@yyds ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'
5050
//注意要在循环体前面加BEGIN,否则无输出

数组

[root@yyds ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday

[root@yyds ~]#ss -nta|awk 'NR!=1{state[$1]++}END{for(i in state){print i,state[i]}}'
LISTEN 11
ESTAB 1

awk脚本

将awk程序写成脚本,直接调用或执行

[root@centos7 ~]#cat test.awk
#!/bin/awk -f
#this is a awk script
{if($3>=1000)print $1,$3}
[root@centos8 ~]#chmod +x test.awk
[root@centos8 ~]#./test.awk -F: /etc/passwd
nobody 65534
wang 1000
mage 1001

三.sed

sed 即 Stream EDitor,和 vi 不同,sed是行编辑器

Sed是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行,再输出一行,直到最后一行。

基本用法

sed [option]... 'script;script;...' [input  file...]
     选项         自身脚本语法         支持标准输入管道

支持管道符

sed常用选项

选项 含义
-e 进行多次编辑
-n 取消默认输出
-f 指定sed文件名
-i 直接在源文件中修改,可以加.xxx备份
-r 使用扩展正则表达式
sed常用命令动作

脚本格式

'地址+命令'组成


1. 不给地址:对全文进行处理(比如行号)
2. 单地址:
   #:指定的行,$:最后一行
   /pattern/:被此处模式所能够匹配到的每一行,正则表达式
3. 地址范围:
   #,#     #从#行到第#行,3,6 从第3行到第6行
   #,+#   #从#行到+#行,3,+4 表示从3行到第7行
   /pat1/,/pat2/    第一个正则表达式和第二个正则表达式之间的行
   #,/pat/  从#号行为开始找到 pat为止 
   /pat/,#  找到#号个pat为止
4. 步进:~
     1~2 奇数行
     2~2 偶数行

命令
p 打印当前模式空间内容,追加到默认输出之后
Ip 忽略大小写输出
d 删除模式空间匹配的行,并立即启用下一轮循环
a [\]text 在指定行后面追加文本,支持使用\n实现多行追加
i [\]text 在行前面插入文本
c [\]text 替换行为单行或多行文本
w file 保存模式匹配的行至指定文件
r file 读取指定文件的文本至模式空间中匹配到的行后
= 为模式空间中的行打印行号
! 模式空间中匹配行取反处理
q           结束或退出sed
[root@yyds ~]#seq 10 | sed 'p'
//带有自动打印功能,p又再打印一遍
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
[root@yyds ~]#seq 10 | sed -n 'p'
1
2
3
4
5
6
7
8
9
10
//-n 选项关闭自动打印功能

[root@yyds ~]#seq 10 | sed -n '3p'
3
//带上地址只显示第三行
支持正则表达式
[root@yyds ~]#sed -n '/root/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
//将包含root的行打印出来  /root(需要匹配的内容)/p(打印)  文件名 
与 grep root /etc/passwd 功能相同

[root@yyds ~]#seq 10|sed -n '3,6p'
3
4
5
6
//显示3到6行
[root@yyds ~]#seq 10|sed -n '3,+4p'
3
4
5
6
7
//3 往后加4行

[root@yyds ~]#sed -n '/^b/,/^f/p' /etc/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
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
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
//可以匹配 两个正则表达式之间的行
先开始找b开头一直找到f开头
然后再重新找b开头,一找到f开头,没有f开头就全显示
重复循环
此方法可以在日志中以时间段查找
例如sed -n '/2018:08:09/,/2018:09:42:37/p' access_log

[root@yyds tmp]#seq 10 |sed -n '1~2p'
1
3
5
7
9


[root@yyds tmp]#sed -n '/nologin/!p' /tmp/passwd
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
test:x:1000:1000:test:/home/test:/bin/bash
test1:x:1001:1001::/home/test1:/bin/bash
test2:x:1002:1002::/home/test2:/bin/bash
test3:x:1003:1003::/home/test3:/bin/bash
test4:x:1004:1004::/home/test4:/bin/bash
test5test6:x:1005:1005::/home/test5test6:/bin/bash
//取反处理

[root@yyds tmp]#sed -n '/root/='  /tmp/passwd
1
10
//显示root所在行的行号

[root@yyds tmp]#sed -n '/root/=;/root/p'  /tmp/passwd
1
root:x:0:0:root:/root:/bin/bash
10
operator:x:11:0:operator:/root:/sbin/nologin
//多个模式匹配要使用分号或者-e

sed -n '$=' zz.txt  相当于统计文件有几行

sed默认不支持扩展正则,如果要支持,需要加-r选项

[root@yyds ~]# sed -n '/^root|^shutdown/p' /etc/passwd
[root@yyds ~]#
[root@yyds ~]# sed -nr '/^root|^shutdown/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

增加

[root@yyds tmp]#sed '3ihello\nworld' /tmp/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
hello
world
daemon:x:2:2:daemon:/sbin:/sbin/nologin
//在第三行之前增加hello换行增加world
i变为a则为在此行之后
可以3,5指定范围为3-5行

[root@yyds tmp]#sed '/test5test6/a hello world' /tmp/passwd
test5test6:x:1005:1005::/home/test5test6:/bin/bash
hello world
//可以匹配到行再增加

删除

[root@localhost ~]# sed '1d' /tmp/passwd
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
//删除第一行

[root@localhost ~]# sed '1,4d' /tmp/passwd
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
     6  sync:x:5:0:sync:/sbin:/bin/sync
     7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
     8  halt:x:7:0:halt:/sbin:/sbin/halt
//删除1-4行

[root@localhost ~]# sed '/nologin/d' /tmp/passwd
     1  root:x:0:0:root:/root:/bin/bash
     6  sync:x:5:0:sync:/sbin:/bin/sync
     7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
     8  halt:x:7:0:halt:/sbin:/sbin/halt
    44  shengjie:x:1000:1000:shengjie:/home/shengjie:/bin/bash
    47  user1:x:1001:1003::/home/user1:/bin/bash
//删除有nologin的行

sed '/^#/d;/^$/d' file
//删除#号开头的行,和空行

替换

[root@yyds tmp]#sed '/root/cxxx' /etc/passwd
xxx
//将root行替换为xxx

这里没有真的改变文件内容,只是输出到屏幕,如果想要真的替换,需要用-i选项,建议用-i之前对原文件进行备份,或者sed -i.bak ‘p’ file

搜索替换

c指令使得整行内容全部替换,d指令删除整行,如果要只替换某个关键词的话需要使用s指令

格式:sed 选项 ‘s/搜索的内容/替换的内容/动作’

[root@yyds ~]#sed 's/root/ROOT/' /tmp/passwd
ROOT:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/ROOT:/sbin/nologin
//搜索root所在行把第一个出现的root换成ROOT
[root@yyds ~]#sed -n 's/root/ROOT/gp' /tmp/passwd
ROOT:x:0:0:ROOT:/ROOT:/bin/bash
operator:x:11:0:operator:/ROOT:/sbin/nologin
//搜索root所在行,把所有出现的root都替换成ROOT

[root@yyds ~]#sed -n 's/o/O/2p' /tmp/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
shutdown:x:6:0:shutdOwn:/sbin:/sbin/shutdown
mail:x:8:12:mail:/var/spoOl/mail:/sbin/nologin
operatOr:x:11:0:operator:/root:/sbin/nologin
//搜索字母o,仅替换每行第 二 个o为大写O

[root@yyds ~]#sed -n 's/root//gp' /tmp/passwd
:x:0:0::/:/bin/bash
operator:x:11:0:operator:/:/sbin/nologin
//将所有root替换为空

[root@yyds ~]#sed  -n '1,5s/^/#/gp' /tmp/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-5行的开头都插入#号

[root@yyds ~]#sed -n 's/\/sbin\/nologin/yyds/gp' /tmp/passwd
bin:x:1:1:bin:/bin:yyds
daemon:x:2:2:daemon:/sbin:yyds
adm:x:3:4:adm:/var/adm:yyds
lp:x:4:7:lp:/var/spool/lpd:yyds
........
//把所有/sbin/nologin换成yyds,/需要转义
其实替换用法与vim类似,“s///”中的/只是用来分隔的,换成###也行,这样不容易混乱

[root@yyds ~]#sed -n 's/^sync/#&/gp' /etc/passwd
#sync:x:5:0:sync:/sbin:/bin/sync
[root@yyds ~]#sed -n 's/^sync/#/gp' /etc/passwd
#:x:5:0:sync:/sbin:/bin/sync
//如果不加&,那么直接将sync替换掉,不保留

[root@yyds ~]# sed -n 's/network/ooooo/igp' /tmp/passwd
systemd-ooooo:x:192:192:systemd ooooo Management:/:/sbin/nologin
[root@yyds ~]# sed -n 's/network/ooooo/gp' /tmp/passwd
systemd-ooooo:x:192:192:systemd Network Management:/:/sbin/nologin
//i忽略大小写

插入文件

[root@yyds ~]#sed '3r /etc/hosts' /tmp/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
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
.......
//r可以将其他文件内容插入指定行号之后

[root@yyds tmp]#sed '/3/r /etc/hosts' /tmp/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
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
//寻找到有3的行,在之后行插入

另存到文件

使用w指令将当前编辑的文件内容另存到其他文件中,如果目标文件已存在,则会将目标文件的内容覆盖

[root@yyds tmp]#sed 'w /tmp/aaaaaa' /tmp/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
....

[root@yyds tmp]#sed '2w /tmp/passwd' /etc/passwd
[root@yyds tmp]#cat passwd 
bin:x:1:1:bin:/bin:/sbin/nologin
//只存第二行

分组操作

当我们需要对一行数据进行多次操作的时候我们可以使用()进行分组

[root@yyds tmp]#echo /etc/sysconfig/network-scripts/ifcfg-ens33 |sed -nr 's@^(.*)/([^/]+)@\2@p'
ifcfg-ens33
//使用此方法要使用扩展正则表达式来表示整行内容,再对想要操作的内容进行分组,第一个()就表示第一个分组,不过如果不同行之间内容格式不一样,那么无法套用之前的表达式,所以一般用来对相同格式的内容进行处理

读取完退出

正常情况下sed会在读取完所有数据行之后退出,但是我们可以随时使用q指令来提前退出sed

[root@yyds tmp]#sed '3q' /tmp/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
//读取完3行不会继续默认打印,直接退出

q不要和-i一起使用,以免覆盖源文件

sed脚本

我们可以先将所有的sed指令写入一个文本文件中,然后通过sed的-f选项读取该指令文件即可实现多指令操作

[root@yyds tmp]#vim test.sh
#!/bin/sed -f
1c hello world
2{
        p
        s/b/B/
}
/root/{
        s/x/H/
        s/root/ROOT/
}


[root@yyds tmp]#sed -f test.sh /tmp/passwd
hello world
bin:x:1:1:bin:/bin:/sbin/nologin
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
........

注意:

  • sed脚本文件第一行要声明#!/bin/sed -f
  • 不要加单引号
  • 每行的最后不能有空格等多余字符
  • #号开头为注释
  • 一行有多个命令时用分号隔开

sed的返回值一般情况为0,不管是不是修改成功了,除非是语法错误

所以sed的返回值$?一般不作为sed成功的判断条件

sed高级应用

-r匹配正则

[root@yyds ~]# sed -r s/^[\t]*/#/ /tmp/hosts
#       127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
#::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

结合变量

[root@yyds tmp]#sed '1a$word'  /tmp/hosts 
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
$word
//单引号表示强引用,不识别变量
[root@yyds tmp]#sed '1a'"$word"  /tmp/hosts 
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
1122
[root@yyds tmp]#sed 1a$word  /tmp/hosts 
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
1122
[root@yyds tmp]#sed ''1a$word''  /tmp/hosts 
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
1122


[root@yyds tmp]#sed '$a'"$word" 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
........
test4:x:1004:1004::/home/test4:/bin/bash
test5test6:x:1005:1005::/home/test5test6:/bin/bash
1122
[root@yyds tmp]#sed "$a$word" passwd 
sed:-e 表达式 #1,字符 4:遗漏命令
//只用双引号不行
[root@yyds tmp]#sed "\$a$word" passwd 
//或者使用转义符来表示$为最后一行而不是变量

你可能感兴趣的:(服务器,linux,运维,centos)