sed
http://blog.oldboyedu.com/commands-sed/
http://coolshell.cn/articles/9104.html
http://www.gnu.org/software/sed/manual/sed.html
http://sed.sourceforge.net/sed1line_zh-CN.html
功能概括
增删改查,过滤,取行
执行的流程
Sed软件从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行,再输出一行……
模式空间:sed软件内部的一个临时缓存,用于存放读取到的内容。
示例1
# 示例文本
cat /etc/person.txt
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
$ cat test.txt
a
b
a
增:a追加与i插入
# 单行
sed '2a 106,dandan,CSO' person.txt
sed '2i 106,dandan,CSO' person.txt
# 多行
sed '2a 106,dandan,CSO\n107,bingbing,CCO' person.txt
# 一行结束,命令未输完可以用\(反斜线)
指定执行的地址范围
用法:n1[,n2]{sed-commands}
地址用逗号分隔的,n1,n2可以用数字、正则表达式、或二者的组合表示。
例子:
10{sed-commands} 对第10行操作
10,20{sed-commands} 对10到20行操作,包括第10,20行
10,+20{sed-commands} 对10到30(10+20)行操作,包括第10,30行
1~2{sed-commands} 对1,3,5,7,……行操作(等差数列)
10,${sed-commands} 对10到最后一行($代表最后一行)操作,包括第10行
/oldboy/{sed-commands} 对匹配oldboy的行操作
/oldboy/,/Alex/{sed-commands} 对匹配oldboy的行到匹配Alex的行操作
/oldboy/,${sed-commands} 对匹配oldboy的行到最后一行操作
/oldboy/,10{sed-commands} 对匹配oldboy的行到第10行操作,注意:如果前10行没有匹配到oldboy,sed软件会显示10行以后的匹配oldboy的行,如果有。
1,/Alex/{sed-commands} 对第1行到匹配Alex的行操作
/oldboy/,+2{sed-commands} 对匹配oldboy的行到其后的2行操作
删:d
# 全部删除
sed 'd' person.txt
sed '2d' person.txt
sed '2,5d' person.txt
sed '3,$d' person.txt
sed '1~2d' person.txt
sed '1,+2d' person.txt
sed '/zhangyao/d' person.txt
sed '/oldboy/,/Alex/d' person.txt
sed '/oldboy/,3d' person.txt
改:c/s
c:按行替换,新行替换旧行
s:文本替换
s:单独使用→将每一行中第一处匹配的字符串进行替换 ==>sed命令
g:每一行进行全部替换 ==>sed命令s的替换标志之一,非sed命令
-i:修改文件内容 ==>sed软件的选项
sed '2c 106,dandan,CSO' person.txt
sed软件替换模型(方框▇被替换成三角▲)
sed -i 's/▇/▲/g' oldboy.log
sed -i 's#▇#▲#g' oldboy.log
观察特点
- 两边是引号,引号里面的两边分别为
s
和g
,中间是三个一样的字符/
或#
作为定界符。#
能在替换内容包含/
有助于区别。定界符可以是任意符号如:
或|
等,但当替换内容包含定界符时,需转义即:
|
。经过长期实践,建议大家使用#
作为定界符。 - 定界符
/
或#
,第一个和第二个之间的就是被替换的内容,第二个和第三个之间的就是替换后的内容。 -
s#▇#▲#g
,▇能用正则表达式,但▲不能用,必须是具体的。 - 默认sed软件是对模式空间(内存中的数据)操作,而-i选项会更改磁盘上的文件内容。
sed 's#zhangyao#oldboyedu#g' person.txt
sed -i 's#zhangyao#BBB#g' person.txt
变量替换
$ x=a
$ y=b
$ echo $x $y
a b
$ sed s#$x#$y#g test.txt
b
b
b
$ sed 's#$x#$y#g' test.txt
a
b
a
$ sed 's#'$x'#'$y'#g' test.txt
b
b
b
$ sed "s#$x#$y#g" test.txt
b
b
b
$ eval sed 's#$x#$y#g' test.txt
b
b
b
分组替换
sed软件的( )的功能可以记住正则表达式的一部分,其中,\1为第一个记住的模式即第一个小括号中的匹配内容,\2第二记住的模式,即第二个小括号中的匹配内容,sed最多可以记住9个。
# echo I am oldboy teacher.如果想保留这一行的单词oldboy,删除剩下的部分,使用圆括号标记想保留的部分。
[root@oldboy ~]# echo I am oldboy teacher. |sed 's#^.*am \([a-z].*\) tea.*$#\1#g'
oldboy
[root@oldboy ~]# echo I am oldboy teacher. |sed -r 's#^.*am ([a-z].*) tea.*$#\1#g'
oldboy
[root@oldboy ~]# echo I am oldboy teacher. |sed -r 's#I (.*) (.*) teacher.#\1\2#g'
amoldboy
特殊符号&
代表被替换的内容
sed '1,3s#C#--&--#g' person.txt #→此处&等于C
查:p
p 输出指定内容,但默认会输出2次匹配的结果,因此使用n取消默认输出
# 按行查询(取行用sed最简单)
sed '2p' person.txt
sed -n '2p' person.txt
sed -n '2,3p' person.txt
sed -n '1~2p' person.txt
sed -n 'p' person.txt
# 按字符查询
sed -n '/CTO/p' person.txt
sed -n '/CTO/,/CFO/p' person.txt
# 混合查询
sed -n '2,/CFO/p' person.txt
sed -n '/feixue/,2p' person.txt
# 特殊情况,前两行没有匹配到feixue,就向后匹配,如果匹配到feixue就打印此行。
案例
案例1:修改sshd配置文件
/etc/ssh/sshd_config
Port 52113
PermitRootLogin no
PermitEmptyPasswords no
UseDNS no
GSSAPIAuthentication no
cp /etc/ssh/sshd_config .
sed -i '$i Port 52113\nPermitRootLogin no\nPermitEmptyPasswords no\nUseDNS no\nGSSAPIAuthentication no' sshd_config
案例2:打印文件内容但不包含oldboy
sed '/oldboy/d' person.txt
案例3:指定行修改配置文件
# 指定行精确修改配置文件,这样可以防止修改多了地方。
sed '3s#0#9#' person.txt
案例4:系统开机启动项优化
chkconfig --list|grep "3:on"|grep -vE "sshd|crond|network|rsyslog|sysstat"|awk '{print $1}'|sed -r 's#^(.*)#chkconfig \1 off#g'|bash
案例5:批量重命名文件
stu_102999_1_finished.jpg
stu_102999_2_finished.jpg
stu_102999_3_finished.jpg
stu_102999_4_finished.jpg
stu_102999_5_finished.jpg
# 重命名效果
stu_102999_1_finished.jpg==>stu_102999_1.jpg
find ~ -type f -name "*.jpg" | sed -r 's/(^.*)_finished(\.jpg)/mv & \1\2/g' | bash
实例2
# 示例文件
$ cat pets.txt
This is my cat
my cat's name is betty
This is my dog
my dog's name is frank
This is my fish
my fish's name is george
This is my goat
my goat's name is adam
$ cat html.txt
html.txt: <b>This</b> is what <span style="text-decoration: underline;">I</span> meant. Understand?
$ cat my.txt
This is my cat, my cat's name is betty
This is my dog, my dog's name is frank
This is my fish, my fish's name is george
This is my goat, my goat's name is adam
$ cat t.txt
one
two
three
s命令:替换
# 把其中的my字符串替换成Hao Chen’s
sed "s/my/Hao Chen's/g" pets.txt
# 把结果写到文件
sed "s/my/Hao Chen's/g" pets.txt > hao_pets.txt
# 直接修改文件内容
sed -i "s/my/Hao Chen's/g" pets.txt
# 在每一行最前面加点东西
sed 's/^/#/g' pets.txt
# 在每一行最后面加点东西
sed 's/$/ --- /g' pets.txt
# 替换html中的标签
sed 's/<[^>]*>//g' html.txt
# 只替换第3到第6行的文本
sed '3,6s/my/your/g' pets.txt
# 只替换每一行的第一个s
sed 's/s/S/' my.txt
# 只替换每一行的第二个s
sed 's/s/S/g2' my.txt
# 只替换第一行的第3个以后的s
sed 's/s/S/g3' my.txt
# 第一个模式把第一行到第三行的my替换成your,第二个则把第3行以后的This替换成了That
sed '1,3s/my/your/g; 3,$s/This/That/g' my.txt
sed -e '1,3s/my/your/g' -e '3,$s/This/That/g' my.txt
# 对匹配的单词两边加[]
sed 's/my/[&]/g' my.txt
# 使用圆括号匹配的示例:(圆括号括起来的正则表达式所匹配的字符串会可以当成变量来使用,sed中使用的是\1,\2…)
# my.txt中,输出 动物:名字
sed 's/This is my \([^,]*\),.*is \(.*\)/\1:\2/g' my.txt
正则为:This is my ([^,]*),.*is (.*)
匹配为:This is my (cat),……….is (betty)
然后:\1就是cat,\2就是betty
# 使用扩展正则表达式
sed -r 's/This is my ([^,]*),.*is (.*)/\1:\2/g' my.txt
# 关于address可以使用相对位置
# 其中的+3表示后面连续3行
sed '/dog/,+3s/^/# /g' pets.txt
N命令
把下一行的内容纳入当成缓冲区做匹配
# 把原文本中的偶数行纳入奇数行匹配,而s只匹配并替换一次(把两行合并成一行,再进行匹配)
sed 'N;s/my/your/' pets.txt
sed 'N;s/\n/,/' pets.txt
a命令和i命令
a命令就是append, i命令就是insert,它们是用来添加行的
# 其中的1i表明,其要在第1行前插入一行(insert)
sed "1 i This is my monkey, my monkey's name is wukong" my.txt
# 其中的1a表明,其要在最后一行后追加一行(append)
sed "$ a This is my monkey, my monkey's name is wukong" my.txt
c命令
替换匹配行
sed "2 c This is my monkey, my monkey's name is wukong" my.txt
sed "2s/^.*$/This is my monkey, my monkey's name is wukong/g" my.txt
sed "/fish/c This is my monkey, my monkey's name is wukong" my.txt
d命令
删除匹配行
sed '/fish/d' my.txt
sed '2d' my.txt
sed '2,$d' my.txt
p命令
打印命令 你可以把这个命令当成grep式的命令
# 匹配fish并输出,可以看到fish的那一行被打了两遍,
# 这是因为sed处理时会把处理的信息输出
sed '/fish/p' my.txt
# 使用n参数就好了
sed -n '/fish/p' my.txt
# 从一个模式到另一个模式
sed -n '/dog/,/fish/p' my.txt
#从第一行打印到匹配fish成功的那一行
sed -n '1,/fish/p' my.txt
命令打包
cmd可以是多个,它们可以用分号分开,可以用大括号括起来作为嵌套命令
# 对3行到第6行,执行命令/This/d
sed '3,6 {/This/d}' pets.txt
# 对3行到第6行,匹配/This/成功后,再匹配/fish/,成功后执行d命令
sed '3,6 {/This/{/fish/d}}' pets.txt
# 从第一行到最后一行,如果匹配到This,则删除之;如果前面有空格,则去除空格
sed '1,${/This/d;s/^ *//g}' pets.txt
Hold Space
第三个我们再来看一下 Hold Space
接下来,我们需要了解一下Hold Space的概念,我们先来看四个命令:
g: 将hold space中的内容拷贝到pattern space中,原来pattern space里的内容清除
G: 将hold space中的内容append到pattern space\n后
h: 将pattern space中的内容拷贝到hold space中,原来的hold space里的内容被清除
H: 将pattern space中的内容append到hold space\n后
x: 交换pattern space和hold space的内容
hold space只是在两次处理cycles间临时可以用于保存内容的buffer,必要时以避免pattern space第一次处理后的结果被第二次读取覆盖
# demo1
sed 'H;g' t.txt
# 反序了一个文件的行
sed '1!G;h;$!d' t.txt
# 1!G —— 只有第一行不执行G命令,将hold space中的内容append回到pattern space
# h —— 第一行都执行h命令,将pattern space中的内容拷贝到hold space中
# $!d —— 除了最后一行不执行d命令,其它行都执行d命令,删除当前行