[TOC]

0x00 快速入门

描述:功能强大的流式文本编辑器(流编辑器-Stream editor)进行文本过滤与格式化替换输出,是在进行文本处理中非常实用的工具,能够完美的配合正则表达式使用;

Sed主要用来自动编辑一个或多个文件,简化对文件的反复操作,编写转换程序等,处理时把当前处理的行存储在临时缓冲区中,称“模式空间”(pattern space),可以指定仅仅处理哪些行

+ sed 命令脑图

Sed执行流程:

  • 将要处理的文本文件通过指定文本文件路径或者管道输入;
  • 循环读取文本中的行到模式空间,进行判断是否要被处理的行;
  • 执行sed命令进行进一步的处理缓冲区中的内容;
  • 打印模式空间 / 清空模式空间;
  • 读取下一行直至文本结束,并将结果输出或者重定向存储输出;

sed 软件有两个内置的存储空间:

  • 模式空间(pattern space) : 是处理时把当前处理的行存储在临时缓冲区中接着用sed命令处理操作模式空间,处理完成后把缓冲区的内容送往屏幕,接着处理下一行这样不断重复直到文件末尾;
  • 保持空间(hold space) :是sed的另外一个缓冲区,用来存放临时数据,sed可以交换保持空间与模式空间数据,但不能在保持空间上执行普通的sed命令;

备注:初始情况下,模式空间和保持空间都是没有内容的,每次循环读取数据的过程中,模式空间的内容都会被清空写入新的内容,但保持空间的内容保持不变,不会再循环中被删除;

命令格式

1
2
3
4
5
6
7
8
# sed 选项  sed-命令 文件|标准输入|管道符
sed [options] 'command' files #文件:指定待处理的文本文件列表或者通过管道符(支持多个文件)
sed [options] -f scriptfile files
sed '[地址范围|模式范围] s#{被替换的字符串}#{替换后的字符串}#{替换标准}' [输入文件]

#组合多个表达式
sed '表达式' | sed '表达式' #等价于下面这一条sed语句
sed '表达式; 表达式'


Sed命令的选项

1
2
3
4
5
6
#选项参数
-e <script>或--expression=<script>:#以选项中的指定的script来处理编辑输入的文本文件,可以执行多条sed命令
-f <script文件>或--file=<script文件>:#以选项中指定的script文件来处理输入的文本文件
-i :#用于sed修改的结果直接修改读取数据的文件,而不有Screen输出.(直接在源文件里加入)
-n或--quiet或--silent:#只列出结果sed特殊处理的那一行,不显示原来那一行
-r :支持扩展表达式sed里面()就不需要使用\();

示例解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sed 'Ms#[源字符串]#[替换的字符]#[Ns|N]' file
#Ms : 对第M行操作 无g标志对匹配的第1列处理;有g则对着一行操作;
#Ng : 从第N处/列后面全部开始替换
#Ms Ng : 对第M行从第N出开始匹配替换
#N :从N处进行匹配替换一次 1<N<512

[[email protected] tmp]# sed '2s#1#0#2' test.txt
1 1 1 1 1
1 0 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
[[email protected] tmp]# sed '2s#1#0#2g' test.txt
1 1 1 1 1
1 0 0 0 0
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1


0x01 命令替换标记

sed命令标志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
a 在当前行下面插入文本。
i 在当前行上面插入文本。
c 把选定的行改为新的文本(类似于替换)。
d 删除选择的行
D 删除模板块的第一行
s 替换指定字符
h 拷贝模板块的内容到内存中的缓冲区。
H 追加模板块的内容到内存中的缓冲区。
g 获得内存缓冲区的内容,并替代当前模板块中的文本。
G 获得内存缓冲区的内容,并追加到当前模板块文本的后面。
l 打印显示特殊字符(行尾以及tab标志)
n 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令。
N 追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。
p 显示打印模板块的行。
P(大写) 打印模板块的第一行。
q 退出Sed。
b lable 分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾。
r file 从file中读行。
t label if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
T label 错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
w file 写并追加模板块到file末尾。
W file 写并追加模板块的第一行到file末尾。
! 表示后面的命令对所有没有被选定的行发生作用。
= 打印当前行号码。
# 把注释扩展到下一个换行符以前。


sed替换标记

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1-512 数字标志确定处理第几个字符处开始处理,
i 忽略大小写进行替换/匹配/查找
\l 小写的l,它会把紧跟再其后面的字符当作小写字符来处理
\L 大写的L,他会把后面所有的字符都当作小写字符来处理
\u 他会紧跟在其后的字符当作大写字符来处理
\U 他会把后面的所有的字符当作大写字符来处理
\E 需要和\U和\L标志使用,他会把后面的所有字符都当作大写字符来处理
e 执行命令标志,将模式空间的任何内容当作bash命令执行
g 表示行内全面替换。
p 表示打印行。
w 表示把行写入一个文件。
x 表示互换模板块中的文本和缓冲区中的文本。
y 表示把一个字符翻译为另外的字符(但是不用于正则表达式)
\1 子串匹配标记
& 已匹配字符串标记


sed元字符集-即正则表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
^ 匹配行开始,如:/^sed/匹配所有以sed开头的行。
$ 匹配行结束,如:/sed$/匹配所有以sed结尾的行。
. 匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d。
* 匹配0个或多个字符,如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行。
[] 匹配一个指定范围内的字符,如/[ss]ed/匹配sed和Sed。
[^] 匹配一个不在指定范围内的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行。
\(..\) 匹配子串,保存匹配的字符,如s/\(love\)able/\1rs,loveable被替换成lovers。
& 保存搜索字符用来替换其他字符,如s/love/**&**/,love这成**love**。
\< 匹配单词的开始,如:/\<love/匹配包含以love开头的单词的行。
\> 匹配单词的结束,如/love\>/匹配包含以love结尾的单词的行。
x\{m\} 重复字符x,m次,如:/0\{5\}/匹配包含5个0的行。
x\{m,\} 重复字符x,至少m次,如:/0\{5,\}/匹配至少有5个0的行。
x\{m,n\} 重复字符x,至少m次,不多于n次,如:/0\{5,10\}/匹配5~10个0的行。


0x02 sed选项案例

定界符
描述:在sed中常用字符 / 作为定界符使用,当然您也可以使用任意的定界符;当定界符出现在样式内部时,需要进行转义

1
2
3
4
5
6
7
#实例1.常用定界符
sed 's:test:TEXT:g'
sed 's|test|TEXT|g'
sed 's#test#TEXT#g' #推荐方法

#实例2.定界符出现在要被替换的字符串中时候需要进行转义
sed 's/\/bin/\/usr\/local\/bin/g'
WeiyiGeek.自定义定界符

WeiyiGeek.自定义定界符


修改写入i命令实例:
-i选项可以直接修改源文件中替换删除的字符串,也能进行备份将要修改的文件;

1
2
3
4
5
6
7
#采用-i 选项 【.bak文件后缀】,进行正则匹配的时候进行先备份将被替换的文件.bak
$ sed -i.bak -e 's/^\(PASS_MAX_DAYS\).*/\1 90/' /etc/login.defs #以PASS_MAX_DAYS开头 采用字符串匹配标记 \1
sed -i.bak 's#22#OK#g' text.txt #更改的同时进行备份
sed -i.bak '/SELINUX/s/enforcing/disabled/' /etc/sysconfig/selinux #值得学习

#直接在文件中进行末尾负复制添加:
sed -i '4p' file.txt

WeiyiGeek.

WeiyiGeek.


多点编辑e命令实例
-e选项允许在同一行里执行多条命令,常常与下面的-n选项进行联用;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#上面sed表达式的第一条命令删除1至5行,第二条命令用check替换test。
#示例1.命令的执行顺序对结果有影响,如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。
sed -e '1,5d' -e 's/test/check/' file
#和 -e 等价的命令是 --expression:
sed --expression='s/test/check/' --expression='/love/d' file
#或者采用一条sed语句执行多条命令 (以 ; 来分割)
sed 's/test/check/;/love/d' file


#示例2.指定单行或者多行不显示
sed -n -e '2!p' fstab #表示第二行不显示
sed -n -e '2!p;6!p' #表示第2行与第6行不显示
sed -n -e '2,5!p' fstab #表示第2到5行不现实

#示例3. 多条语句执行,表示删除空行并且以#开头的行
sed -e '/^$/d;/^#/d' fstab #^$表示首尾相连,也就是空行


显示操作n命令选项示例
描述:利用-n选项p命令来进行指定行的数据查看并且不显示已改变源文件的那一行;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#实例1.打印需要显示的行
cat -n ReleaseNotes.css | sed -n "10,13P"
10 a {
11 color: #94C3FF;
12 text-decoration: none;
13 }



#示例2.选定行的范围:,(逗号)**
#所有在模板test和check所确定的范围内的行都被打印:
sed -n '/test/,/check/p' file

#打印从第5行开始到第一个包含以test开始的行之间的所有行:
sed -n '5,/^test/p' file

#对于模板test和west之间的行,每行的末尾用字符串aaa bbb替换:
sed '/test/,/west/s/$/aaa bbb/' file


#示例3.打印奇数行或偶数行(s)
#方法1:
sed -n 'p;n' test.txt #奇数行
sed -n 'n;p' test.txt #偶数行
#方法2:sed命令通用的 'n{sed-command}'
sed -n '1~2p' test.txt #奇数行 1 3 5 7 9 ~后面的数字是Step
sed -n '2~2p' test.txt #偶数行 2 4 6 8 10
sed -n '2p' test.txt #打印第二行
sed -n '2,10p' test.txt #打印二至十行
sed -n '2,+20p' test.txt #打印二至十二行
sed -n '/test/,+20p' test.txt #打印test字符串行到,前面行+20行截止
sed -n '2,$ p' test.txt #从第二行答应到末尾 (注意空格)
sed -n '/test/,/text/p' test.txt #打印test字符串行到text字符串的行之间的行 (自己组合上面的来达到各种效果)


#示例2.与正则联用打印
sed -n '/^#/p' fstab #表示显示以#开头的行
sed -n '/^#/!p' fstab #表示以#开头的行不显示
sed -n '/0$/!p' fstab #表示以0结尾的行不显示
sed -n '/0$/p' fstab #表示显示以0结尾结尾的行
sed -n '/^#/!p' /etc/ssh/sshd_config


#实例3.可直接替换配置文件文本
sed -n "s/^\(PermitRootLogin\).*/\1 no/p" /etc/ssh/sshd_config
#PermitRootLogin no

#读取配置文件,利用正则查找指定的行不进行删除(!d)然后替换(s)=号及前的字符串为空;
ReadConfig() {
# 使用方法: ReadConfig <配置文件> <读取参数>
# Example : ReadConfig "/etc/config.cfg" "Parameter"
cat $1 | sed '/^'$2'=/!d;s/.*=//'
}

WeiyiGeek.奇数与偶数行打印

WeiyiGeek.奇数与偶数行打印

_总结_:

  • sed 匹配是贪婪模式匹配到越多;


正则扩展命令sed之-r选项
描述:使用了该-r选择后就能使用正则表达式的扩展语法,在写一些正则符号前无需添加\(

1
2
3
4
#这里url是存储着url的文件:
sed -nr 's/^http:\/\/([0-9.]+):[0-9]+.*$/\1/p' url # 取出IP地址
sed -nr 's/^http:\/\/[0-9.]+:([0-9]+).*$/\1/p' url # 取出端口
sed -nr 's/^http:\/\/[0-9.]+:[0-9]+(.*$)/\1/p' url # 取出后续路径


选项执行脚本中的sed表达式
sed脚本是一个sed的命令清单,启动Sed时以-f选项引导脚本文件名。
Sed对于脚本中输入的命令非常挑剔,在·命令的末尾不能有任何空白或文本,如果在一行中有多个命令,要用分号分隔`以#开头的行为注释行,且不能跨行。

1
2
3
4
5
6
7
8
9
10
sed [options] -f scriptfile file(s)
$ sed -f '脚本文件' file
#建立一个sed脚本文件 sed.script 每一行一条
1,2d
s#1#0#3g

$ sed -f sed.script test.txt
1 1 0 0 0
1 1 0 0 0
1 1 0 0 0


0x03 增删改查命令

单行插入和多行插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#头部插入(行上):i\命令
#将 this is a test line 追加到以test开头的 行前面:
sed '/^test/i\this is a test line' file
#单行插入:在test.conf文件第5行之前插入this is a test line
sed -i '5i\this is a test line' test.conf
#多行插入:在test.conf文件第5行前插入first insert \n seconde insert
sed -i '5i first insert\nseconde insert' test.conf

#尾部追加插入(行下):a\命令
#将 this is a test line 追加到 以test 开头的 行后面:
sed '/^test/a\this is a test line' file
#单行插入:在 test.conf 文件第2行之后插入 this is a test line:
sed -i '2a\this is a test line' test.conf
#多行插入:在test.conf文件第5行后插入first insert \n seconde insert
sed -i '5a first insert\nseconde insert' test.conf

示例1.优化ssh配置文件写入

1
sed -i '13i Port 52113\nPermirRootLogin no\nPermitEmptyPasswords no\nUseDNS no\nGSSAPIAuthentication no' /etc/ssh/sshd_config


删除操作
描述:删除匹配的字符串以及行采用d命令,源文件并没有改变如果改变需要加上选项-i

1
2
3
4
5
6
7
8
#更多格式需要参考:示例3.打印奇数行或偶数行(s)
sed 'd' file #删除文件的所有行
sed '2d' file #删除文件的第2行
sed '2,5d' file #删除文件的第2行到第五行
sed '$d' file #删除文件最后一行
sed '2,$d' file #删除文件的第2行到末尾所有行
sed '/^test/d' file # 删除文件中所有开头是test的行注意是一行
sed '/^$/d' file # 删除空白行

示例2:匹配的行(文本、正则)进行删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#(1) 删除或者不删除指定字符串的行
sed -e '/UUID/d' fstab #表示删除含有UUID的行
sed -e '/UUID/!d' fstab #表示不删除含有UUID的行,也就是只显示含有UUID的行

#(2) 以正则表达式匹配删除
sed -e '/^#/d' fstab #表示删除以#开头的行
sed -e'/^#/d;/^$/d' _config.yml #采用多行命令,后面的命令以前面命令为基础;
# include:
# - .nojekyll
# exclude:
# - .DS_Store
# search:
# path: search.xml
# filed: post


替换操作

描述:替换文本的字符串,采用s命令以及g来进行全局替换,也可以采用c命令指定行替换;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
######### 行替换(多行/单行) ############
#将text.txt文本的第二行替换成为"second insert txt" (支持多行和单行替换)
$ sed '2c second insert \n there txt' text.txt

############## 字符替换操作 ###############
#-n选项和p命令一起使用表示只打印那些发生替换的行(并未写入文件中)
$ sed -n 's/test/TEST/p' file
$ sed 's/book/books/' file #将文件中的第一个book字符串换成books
$ sed '3s/60/90/' file.txt # 将text.txt第三行中得60换成90;

#直接编辑文件-i选项,会匹配file文件中每一行的book替换为books(直接写入到源文件中)
$ sed -i 's/book/books/g' file #使用后缀 /g 标记会替换每一行中的所有匹配:
$ sed -i 's/book/books/4g' file #每行从第四个book字符串开始替换

#开始从第二个匹配字符串进行替换
$ sed 's/test/TEST/2g' www
testTESTTEST
testTESTTEST

################ 变量替换 ################
#sed表达式可以使用单引号来引用,但是如果`表达式内部包含变量字符串,就需要使用双引号`。
test=hello
echo hello WORLD | sed "s/$test/HELLO"
HELLO WORLD


################ 分组替换 ################
描述:就是正则表达式中的元组即\(...\)包含匹配的字符串,即匹配给定样式的其中一部分,
\(..\) 用于匹配子串,对于匹配到的第一个子串就标记为 \1,依此类推匹配到的第二个结果就是 \2,例如:
#实例1.样式匹配到的子串是 7,命令中 digit 7,被替换成了 7
echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
#this is 7 in a number

实际示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#行替换/字符替换
sed "/SELINUX/s/disabled/enforcing/#" etc/selinux/config
sed "/^SELINUX/s/disabled/enforcing/#" /etc/selinux/config

#变量替换
x=a;y=b #将字符a替换成为b(四种形式),
sed "s#$x#$y#g" test.txt
sed s#$x#$y#g test.txt
sed 's#'$x'#'$y'#g' test.txt #注意单引号不能解析变量
eval sed 's#'$x'#'$y'#g' test.txt


#分组替换
#love被标记为1,所有loveable会被替换成lovers,并打印出来.组合多个表达式 (值得学习借鉴)
echo "loveable" | sed -n 's/\(love\)able/\1rs/p;s/\(love\)rs/\1 You/p' #lovers #love You
$echo aaa BBB | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/' #BBB aaa
#传递每行到shell中进行执行
systemctl list-unit-files | grep "disabled" | grep -E "socket"|awk '{print $1}'|sed -r 's#(.*)#systemctl \1 enable#g'|bash
systemctl docker.socket enable
systemctl rsyncd.socket enable
systemctl sshd.socket enable
systemctl tftp.socket enable


已匹配字符串标记 &
描述: 正则表达式 \w+ 匹配每一个单词,使用 [&] 替换它,& 对应于之前所匹配到的单词

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#实例1.用来字符串拼接使用
echo this is a test line | sed 's/\w\+/[&]/g'
#[this] [is] [a] [test] [line]

#所有以192.168.0.1开头的行都会被替换成它自已加localhost:
sed 's/^192.168.0.1/& localhost/' file # & 代表匹配字符串本身
#192.168.0.1 localhost

#批量更改文件名称
$ ls *.jpg | sed -r 's#(.*).finish.*#mv & \1.jpg#' | bash
mv 1_student_10_finish.jpg 1_student_10.jpg
mv 1_student_1_finish.jpg 1_student_1.jpg
mv 1_student_2_finish.jpg 1_student_2.jpg
mv 1_student_3_finish.jpg 1_student_3.jpg
mv 1_student_4_finish.jpg 1_student_4.jpg
mv 1_student_5_finish.jpg 1_student_5.jpg
mv 1_student_6_finish.jpg 1_student_6.jpg
mv 1_student_7_finish.jpg 1_student_7.jpg
mv 1_student_8_finish.jpg 1_student_8.jpg
mv 1_student_9_finish.jpg 1_student_9.jpg
$ ls *.jpg
1_student_1.jpg 1_student_2.jpg 1_student_4.jpg 1_student_6.jpg 1_student_8.jpg
1_student_10.jpg 1_student_3.jpg 1_student_5.jpg 1_student_7.jpg 1_student_9.jpg

WeiyiGeek.已匹配字符串标记

WeiyiGeek.已匹配字符串标记


查操作
描述:采用p命令进行打印常常和-n选项联用,在前面介绍-n的时候有介绍

1
2
3
4
ifconfig | sed -nr 's#([0-9]+\.){3}[0-9]{1,3}#[&]#gp' #打印出匹配的行
inet [192.168.1.99] netmask [255.255.255.0] broadcast [192.168.1.255]
inet [10.10.107.222] netmask [255.255.255.0] broadcast [10.10.107.255]
inet [127.0.0.1] netmask [255.0.0.0]


sed 文件修改,另存为,读取

写入文件:w命令,当然也可以采用重定向的方式也是可以的;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
############## 文件另存为 ####################
#实例1.在example中所有包含test的行都被写入file里:
sed -n '/test/w file' example
sed -n '/test/' example > file


#实例2.将匹配出的IP输出到文件
ifconfig | sed -nr 'sed -nr 's#(([0-9]+\.){3}[0-9]{1,3})#[\1]#g w output.txt'
$ cat output.txt
inet [192.168.1.99] netmask [255.255.255.0] broadcast [192.168.1.255]
inet [10.10.107.222] netmask [255.255.255.0] broadcast [10.10.107.255]

#示例3.通过正则匹配出的行写入到文件中
sed -n '/bash$/p' passwd > file #重定向写入文件
sed -n '/bash$/wfile' passwd #在w模式下,可以直接写入文件,这是追加的过程不会覆盖原文


从文件读入:r命令
描述:file里的内容被读进来,显示在与test匹配的行后面,如果匹配多行,则file的内容将显示在所有匹配行的下面

1
2
3
4
5
6
7
8
9
10
11
#示例1.读取file文件中的到并且插入到查找到test字符串的后面
sed '/test/r file' filename

#示例2.读取passwd
echo -e "User list:" | sed 'r /etc/passwd'
User list:
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


0x04 其他命令

显示文本或者匹配文本的行数=

1
2
3
4
5
6
7
8
9
10
$ getent passwd | sed -n '=;/root/p'
# 1
# root:x:0:0:root:/root:/bin/bash
# 10
# operator:x:11:0:operator:/root:/sbin/nologin

#改进采用N命令来保持模式空间里面的数据
$ getent passwd | sed -n '=;/root/p' | sed 'N;s#\n# #'
1 root:x:0:0:root:/root:/bin/bash
10 operator:x:11:0:operator:/root:/sbin/nologin


忽略大小写进行匹配替换i:

1
2
$ echo "abc ABC" |sed 's#a#W#ig'
Wbc WBC


执行命令标志e的使用:

1
2
3
4
5
6
7
8
9
10
$ cat txt 
RPM-GPG-KEY-weiyigeek
aaa.jpg
compare_varnish.jpg

#将匹配到的文件相当于执行 ls -lh [filename]
$ sed 's#^#ls -lh & #e' txt #注意这里命令后需要空格 & ,否则有一定的报错;
-rw-r--r-- 1 root root 1.1K Jun 20 09:13 RPM-GPG-KEY-weiyigeek
-rw-r--r-- 1 root root 106K Jun 27 17:10 aaa.jpg
-rw-r--r-- 1 root root 106K Jun 27 17:11 compare_varnish.jpg


大小写转换\l \L 与 \u \U;

1
2
3
4
5
6
7
8
9
10
11
12
$ echo "abcdefg" | sed 's#d# WEIYI \lGEEK #p' #符号后的一个字符变成小写
abc WEIYI gEEK efg
$ echo "abcdefg" | sed 's#d# WEIYI \LGEEK #p' #其后所有字母都变小写
abc WEIYI geek efg
$ echo "abcdefG" | sed 's#d# WEIYI \ugeek #p'
abc WEIYI Geek efG
$ echo "abcdefG" | sed 's#d# WEIYI \Ugeek #p'
abc WEIYI GEEK efG

#可以将匹配的字符放在\U|u|l|L后面即可
echo "abcdefG" | sed -nr 's#([a-z]{1,10})# WEIYIGEEK \U\1#p' #全部转成大写
WEIYIGEEK ABCDEFG


大小写变形y命令:注意正则表达式元字符不能使用这个命令

1
2
#把1~10行内所有abcde转变为大写,
sed '1,10y/abcde/ABCDE/' file


特殊符号 {}
描述:包含在{}中的命令按照顺序执行,并且前面命令会影响后面的命令;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#打印匹配字符串的下一行然后并打印
sed -n '/SCC/{n;p}' URFILE # 5字符的下一行就是6 (值得学习)
grep -A 1 SCC URFILE # -A 显示的行数 在字符的下面
awk '/SCC/{getline; print}' URFILE # 5字符的下一行就是6

#只打印指定的行号的选项
sed -n '2,5{=;p}' /etc/passwd
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

#进一步完善
sed -n '2,5{=;p}' /etc/passwd | sed "N;s#\n# #g"
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

WeiyiGeek.补充实例

WeiyiGeek.补充实例


特殊符号 1

描述:打印显示特殊字符(行尾以及tab标志),小写的L;

1
2
3
4
$echo -e  "abc \n cde \n hfg \t qwe " | sed -n 'l'
abc $
cde $
hfg \t qwe $


双引号内的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#退出:q命令
#打印完第10行后,退出sed
sed '10q' file
sed -n '10q;p' /etc/passwd

#保持和互换:h命令和x命令
#互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换:
sed -e '/test/h' -e '/check/x' file


#保持和获取:h命令和G命令
#在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将 打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。
sed -e '/test/h' -e '$G' file #追加到最后一行简单来说,任何包含test的行都被复制并追加到该文件的末尾。不加$则每一行下一行进行显示复制的数据;

#在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。
#第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中的行的末尾。

WeiyiGeek.实例

WeiyiGeek.实例


模式空间
n命令:打印下一行并且清空当前模式空间进入下一次循环
N命令:不清空当前模式空间,然后读入下一行以\n分隔两行;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#n命令示例
#如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb并打印该行
sed '/test/{ n; s/aa/bb/; }' file
sed '/test/{ n;p }' file #打印test字符串的下一行

#N命令示例 (模式空间的\n替换为空)
$ sed -n '10{=;p}' /etc/passwd | sed 'N; s#\n# #g'
10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

#其他用法(值得学习)
$cat txt
name
weiyigeek
age
29
love
computer

$sed 'N;s#\n# = #g' txt
name = weiyigeek
age = 29
love = computer


Sed模拟其他命令
模拟:cat text.txt

1
2
3
4
5
6
#不改动模式空间内容,既可以输入text文件中的全部内容
sed "" text.txt
sed -n 'p' text.txt
sed 'n' text.txt
sed 'N' text.txt
sed 's# # #g' text.txt

模拟:grep -v反过滤

1
2
3
#显示带有字符的行或者不显示带有字符的行
sed -n '/test/ p' text.txt
sed -n '/test/ !p' text.txt

模拟:wc -l命令

1
2
#统计文件中的行数
sed -n "$=" /etc/passwd

内容中的换行符替换
描述:sed是可以处理多行数据的,N是把下一行加入到当前的hold space模式空间里,使之进行后续处理,最后sed会默认打印hold space模式空间里的内容。

基础实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# (方式1):a和ta是配套使用,实现跳转功能,t是test测试的意思。 
sed ":a;N;s/\n//g;ta" file

# test可以根据替换命令的完成是否成功,决定是否跳转,类比下面的伪代码
# while(state == 1) { #注释:默认state就当是1好了。
# N;
# s/\n//g; #注释:成功,返回state为1;否则返回state=0。此state用于跳转判断。
# }else {
# last; #注释:即退出循环语句。
# }

# (方式2):a和ba的配套使用方式,也可以实现跳转功能,b是branch分支的意思。
sed ":a;N;s/\n//g;ba" file
#branch循环到文本结束类比下面的伪代码
# while(1) {
# N;
# s/\n//g;
# }

#比如:增加$!ba语句,$的意思是最后一行,不跳转到标记a处,即退出命令循环(两种写法)。
sed ":a;N;s/\n//g;$!ba" file
sed ":a;$!N;s/\n//g;ba" file

#(方式3).替换\n也就是把所有的行都归为一行
sed ':a;N;$!ba;s/\n/ /g' file.txt

## 实际可以将上面的命令拆分描述,就比较简单多了;
# 多次匹配替换
sed -i -e 's/12_/abc/g' -e 's/aa_/aa_3rth/g' AAA.txt
sed -e ':a' -e 'N' -e '$!ba' -e 's/\n//g' file.txt


在指定字符前后进行添加插入相应字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# -1.在1111之前添加AAA, 方法 sed -i 's/指定的字符/要插入的字符&/'文件
sed -i 's/1111/AAA&/' /tmp/input.txt

# -2.在1111之后添加BBB,方法 sed -i 's/指定的字符/&要插入的字符/' 文件
sed -i 's/1111/&BBB/' /tmp/input.txt

# -3.在每行的头添加字符比如"HEAD"以及在每行的尾部添加字符比如"END", 命令如下:
sed 's/^/HEAD&/;s/$/&END/' /tmp/input.txt

# -4.(1) 删除所有空行;(2) 一行中,如果包含"1111",则在"1111"前面插入"AAA",在"11111"后面插入"BBB"
sed '/^$/d;s/1111/AAA&/;s/1111/&BBB/' /tmp/input.txt

# -5.在包含www.baidu.com的行前面或后面添加多一行内容www.qq.com
# 匹配行前加
sed -i '/www.baidu.com/i www.qq.com' domain.file
# 匹配行后加
sed -i '/www.baidu.com/a www.qq.com' domain.file

# -6.在62行前面或后面添加多一行内容" chmod 644 /data/backup/2015-08-22/* "
# 在指定行前加
sed -i 'N;62 i chmod 644 /data/backup/2015-08-22/*' /home/bin/backup_data.sh
# 在指定行后加
sed -i 'N;62 a chmod 644 /data/backup/2015-08-22/*' /home/bin/backup_data.sh