目录
6.sed 替换命令语法
7.全局标志 g
8.数字标志(1,2,3 ….)
9.打印标志 p(print)
10.写标志 w
11.忽略大小写标志 i (ignore)
12.执行命令标志 e (excuate)
13.使用替换标志组合
14.sed 替换命令分界符
15.单行内容上执行多个命令
16.&的作用——获取匹配到的模式
17.分组替换(单个分组)
18.分组替换(多个分组)
19.GNU Sed 专有的替换标志
流编辑器中最强大的功能就是替换(substitute),其强大的功能和繁多的选项将占据下面整整
一章的内容。
6.sed 替换命令语法
sed ‘[address-range|pattern-range] s/original-string/replacement-string/[substitute-flags]’
input file
上面提到的语法为:
address-range
或
pattern-range(
即地址范围和模式范围
)
是可选的。如果没有指
定,那么
sed
将在所有行上进行替换。
s
即执行替换命令
substitute
original-string
是被
sed
搜索然后被替换的字符串,它可以是一个正则表达式
replacement-string
替换后的字符串
substitute-flags
是可选的,下面会具体解释
请谨记原始输入文件不会被修改,
sed
只在模式空间中执行替换命令,然后输出模式空间的
内容。
下面是一些简单的替换示例(替换的部分用黑体标明)
用 Director 替换所有行中的 Manager:
$ sed 's/Manager/Director/' employee.txt
101,John Doe,CEO
102,Jason Smith,IT
Director
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales
Director
只把包含 Sales 的行中的 Manager 替换为 Director:
$ sed '/Sales/s/Manager/Director/' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales
Director
注意:本例由于使用了地址范围限制,所以只有一个
Manager
被替换了
7.全局标志 g
g 代表全局
(global)
默认情况下,
sed
至会替换每行中第一次出现的
original-string
。如果你要
替换每行中出现的所有
original-string,
就需要使用
g
用大写 A 替换第一次出现的小写字母 a:
$ sed 's/a/A/' employee.txt
101,John Doe,CEO
102,J
A
son Smith,IT Manager
103,R
A
j Reddy,Sysadmin
104,An
A
nd Ram,Developer
105,J
A
ne Miller,Sales Manager
把所有小写字母 a 替换为大写字母 A:
$ sed 's/a/A/g' employee.txt
101,John Doe,CEO
102,J
A
son Smith,IT M
A
nAger
103,R
A
j Reddy,Sys
A
dmin
104,An
A
nd R
A
m,Developer
105,J
A
ne Miller,S
A
les M
A
n
A
ger
注意:上述例子会在所有行上替换,因为没有指定地址范围。
8.数字标志(1,2,3 ….)
使用数字可以指定
original-string
出现的次序。只有第
n
次出现的
original-string
才会触发替
换。每行的数字从
1
开始,最大为
512
。
比如
/11
会替换每行中第
11
次出现的
original-string
下面是几个例子:
把第二次出现的小写字母 a 替换为大写字母 A:
$ sed 's/a/A/2' employee.txt
101,John Doe,CEO
102,Jason Smith,IT M
A
nager
103,Raj Reddy,Sys
A
dmin
104,Anand R
A
m,Developer
105,Jane Miller,S
A
les Manager
为了方面下面示例,请先建立如下文件:
$ vim substitute-locate.txt
locate command is used to locate files
locate command uses database to locate files
locate command can also use regex for searching
使用刚才建立的文件,把每行中第二次出现的 locate 替换为 find:
$ sed 's/locate/find/2' substitute-locate.txt
locate command is used to
find
files
locate command uses database to
find
files
locate command can also use regex for searching
注意:第
3
行中
locate
只出现了一次,所以没有替换任何内容
9.打印标志 p(print)
命令
p
代表
print
。当替换操作完成后,打印替换后的行。与其他打印命令类似,
sed
中比较
有用的方法是和
-n
一起使用以抑制默认的打印操作。
只打印替换后的行:
$ sed -n 's/John/Johnny/p' employee.txt
101,
Johnny
Doe,CEO
在之前的数字标志的例子中,使用
/2
来替换第二次出现的
locate
。第
3
行中
locate
只出现了
一次,所以没有替换任何内容。使用
p
标志可以只打印替换过的两行。
把每行中第二次出现的 locate 替换为 find 并打印出来:
$ sed -n 's/locate/find/2p' substitute-locate.txt
locate command is used to
find
files
locate command uses database to
find
files
10.写标志 w
标志
w
代表
write
。当替换操作执行成功后,它把替换后的结果保存的文件中。多数人更倾
向于使用
p
打印内容,然后重定向到文件中。为了对
sed
标志有个完整的᧿述,在这里把这
个标志也提出来了。
只把替换后的内容写到 output.txt 中:
$ sed -n 's/John/Johnny/w output.txt' employee.txt
$ cat output.txt
101,Johnny Doe,CEO
和之前使用的命令
p
一样,使用
w
会把替换后的内容保存到文件
output.txt
中。
把每行第二次出现的 locate 替换为 find,把替换的结果保存到文件中,同时显示输入文件所
有内容:
$ sed 's/locate/find/2w output.txt' substitute-locate.txt
locate command is used to
find
files
locate command uses database to
find
files
locate command can also use regex for searching
$ cat output.txt
locate command is used to
find
files
locate command uses database to
find
files
11.忽略大小写标志 i (ignore)
替换标志 i
代表忽略大小写。可以使用
i
来以小写字符的模式匹配
original-string
。该标志只
有
GNU Sed
中才可使用。
下面的例子不会把 John 替换为 Johnny,因为 original-string 字符串是小写形式:
$ sed 's/john/Johnny/' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
把 john 或 John 替换为 Johnny:
$ sed 's/john/Johnny/i' employee.txt
101,
Johnny
Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
12.执行命令标志 e (excuate)
替换标志 e
代表执行
(execute)
。该标志可以将模式空间中的任何内容当做
shell
命令执行,
并把命令执行的结果返回到模式空间。该标志只有
GNU Sed
中才可使用。
下面是几个例子:
为了下面的例子,请先建立如下文件:
$ cat files.txt
/etc/passwd
/etc/group
在 files.txt 文件中的每行前面添加 ls –l 并打击结果:
$ sed 's/^/ls -l/' files.txt
ls -l/etc/passwd
ls -l/etc/group
在 files.txt 文件中的每行前面添加 ls –l 并把结果作为命令执行:
$ sed 's/^/ls -l /e' files.txt
-rw-r--r-- 1 root root 1533 Dec 13 20:21 /etc/passwd
-rw-r--r-- 1 root root 682 Dec 13 20:21 /etc/group
13.使用替换标志组合
根据需要可以把一个或多个替换标志组合起来使用。
下面的例子将把每行中出现的所有
Manager
或
manager
替换为
Director
。然后把替换后的内
容打印到屏幕上,同时把这些内容保存到
output.txt
文件中。
使用 g,I,p 和 w 的组合:
$ sed -n 's/manager/Director/igpw output.txt' employee.txt
102,Jason Smith,IT Director
105,Jane Miller,Sales Director
$ cat output.txt
102,Jason Smith,IT Director
105,Jane Miller,Sales Director
14.sed 替换命令分界符
上面所有例子中,我们都是用了
sed
默认的分界符
/,
即
s/original-string/replacement-string/g
如果在
original-string
或
replacement-string
中有
/,
那么需要使用反斜杠
\
来转义。
为了便于示 例,请先建立下面文件:
$ vi path.txt
$ cat path.txt
reading /usr/local/bin directory
限制使用 sed 把/usr/local/bin 替换为/usr/bin。在下面例子中,sed 默认的分界符/都被\转义 了:
$ sed 's/\/usr\/local\/bin/\/usr\/bin/' path.txt
reading /usr/bin directory
很难看,不是吗?如果要替换一个很长的路径,每个
/
前面都使用
\
转义,会显得很混乱。幸
运的是,你可以使用任何一个字符作为
sed
替换命令的分界符,如
|
或
^
或
@
或者
!
。
下面的所有例子都比较易读。这里不再显示下面例子的结果,因为它们的结果和上面的例子
是相同的。我个人比较倾向于使用@或者!来替换路径,但使用什么看你自己的偏好了。
sed ‘s|/usr/local/bin|/usr/bin|’ path.txt
sed ‘s^/usr/local/bin^/usr/bin^’ path.txt
sed ‘s@/usr/local/bin@/usr/bin@’ path.txt
sed ‘s!/usr/local/bin!/usr/bin!’ path.txt
15.单行内容上执行多个命令
一如之前所说,sed
执行的过程是读取内容、执行命令、打印结果、重复循环。其中执行命
令部分,可以由多个命令执行,
sed
将一个一个地依次执行它们。
例如,你有两个命令,
sed
将在模式空间中执行第一个命令,然后执行第二个命令。如果第
一个命令改变了模式空间的内容,第二个命令会在改变后的模式空间上执行
(
此时模式空间
的内容已经不是最开始读取进来的内容了
)
。
下面的例子演示了在模式空间内执行两个替换命令的过程:
把
Developer
替换为
IT Manager,
然后把
Manager
替换为
Director:
$ sed '{
> s/Developer/IT Manager/
> s/Manager/Director/
> }' employee.txt
101,John Doe,CEO
102,Jason Smith,IT
Director
103,Raj Reddy,Sysadmin
104,Anand Ram,
IT Director
105,Jane Miller,Sales
Director
我们来分析下第
4
行的执行过程:
1.
读取数据
:在这一步,
sed
读取内容到模式空间,此时模式空间的内容为:
104,Anand Ram,Developer
2.
执行命令:
第一个命令,
s/Developer/IT Manager/
执行后,模式空间的内容为
:
104,Anand Ram,IT Manager
现在在模式空间上执行第二个命令
s/Manager/Director/,
执行后,模式空间内容为
:
104,Anand Ram,IT Director
谨记:
sed
在第一个命令执行的结果上,执行第二个命令。
3.
打印内容
:
打印当前模式空间的内容,如下
:
104,Anand Ram,IT Director
4.
重复循环:
移动的输入文件的下一行,然后重复执行第一步,即读取数据
16.&的作用——获取匹配到的模式
当在
replacement-string
中使用
&
时,它会被替换成匹配到的
original-string
或正则表达式,这
是个很有用的东西。
看下面示例:
给雇员 ID(即第一列的 3 个数字)加上[ ],如 101 改成[101]
$ sed 's/^[0-9][0-9][0-9]/[&]/g' employee.txt
[101],John Doe,CEO
[102],Jason Smith,IT Manager
[103],Raj Reddy,Sysadmin
[104],Anand Ram,Developer
[105],Jane Miller,Sales Manager
把每一行放进< >中:
$ sed 's/^.*/<&>/' employee.txt
<101,John Doe,CEO>
<102,Jason Smith,IT Manager>
<103,Raj Reddy,Sysadmin>
<104,Anand Ram,Developer>
<105,Jane Miller,Sales Manager>
17.分组替换(单个分组)
跟在正则表达式中一样,
sed
中也可以使用分组。分组以
\(
开始,以
\)
结束。分组可以用在
回溯引用中。
回溯引用即重新使用分组所选择的部分正则表达式,在
sed
替换命令的
replacement-string
中和正则表达式中,都可以使用回溯引用。
单个分组:
$ sed 's/\([^,]*\).*/\1/g' employee.txt
101
102
103
104
105
上面例子中:
z
正则表达式
\([^,]*\)
匹配字符串从开头到第一个逗号之间的所有字符
(
并将其放入第
一个分组中
)
z
replacement-string
中的
\1
将替代匹配到的分组
z
g
即是全局标志
下面这个例子只会显示/etc/passwd 的第一列,即用户名:
$ sed 's/\([^:]*\).*/\1/' /etc/passwd
下面的例子,如果单词第一个字符为大写,那么会给这个大写字符加上()
$ echo "The Geek Stuff"|sed 's/\(\b[A-Z]\)/\(\1\)/g'
(T)he (G)eek (S)tuff
请先建立下面文件,以便下面的示例使用:
$ vim numbers.txt
1
12
123
1234
12345
123456
格式化数字,增加其可读性
:
$ sed 's/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g' numbers.txt
1
12
123
1,234
12,345
123,456
18.分组替换(多个分组)
你可以使用多个
\(
和
\)
划分多个分组,使用多个分组时,需要在
replacement-string
中使用
\n
来指定第
n
个分组。如下面的示例。
只打印第一列(雇员 ID)和第三列(雇员职位):
$ sed 's/^\([^,]*\),\([^,]*\),\([^,]*\)/\1,\3/' employee.txt
101,CEO
102,IT Manager
103,Sysadmin
104,Developer
105,Sales Manager
在这个例子中,可以看到,
original-string
中,划分了
3
个分组,以逗号分隔。
z
([^,]*\)
第一个分组,匹配雇员
ID
z
,为字段分隔符
z
([^,]*\)
第二个分组,匹配雇员姓名
z
,为字段分隔符
z
([^,]*\)
第三个分组,匹配雇员职位
z
,为字段分隔符,上面的例子演示了如何使用分组
z
\1
代表第一个分组
(
雇员
ID)
z
,出现在第一个分组之后的逗号
z
\3
代表第二个分组
(
雇员职位
)
注意:
sed
最多能处理
9
个分组,分别用
\1
至
\9
表示。
交换第一列
(
雇员
ID)
和第二列
(
雇员姓名
)
:
$ sed 's/^\([^,]*\),\([^,]*\),\([^,]*\)/\2,\1,\3/' employee.txt
John Doe,101,CEO
Jason Smith,102,IT Manager
Raj Reddy,103,Sysadmin
Anand Ram,104,Developer
Jane Miller,105,Sales Manager
19.GNU Sed 专有的替换标志
下面的标志,只有
GNU
版的
sed
才能使用。它们可以用在替换命令中的
replacement-string
里面
.
\l
标志 当在 replacement-string
中使用
\l
标志时,它会把紧跟在其后面的字符当做小写字符来处理。
如你所知,下面的例子将把 John 换成 JOHNNY:
sed ‘s/John/JOHNNY/’ employee.txt
下面的例子,在 replacement-string 中的 H 前面放置了\l 标志,它会把 JOHNNY 中的 H 换成
小写的 h:
$ sed -n 's/John/JO\lHNNY/p' employee.txt
101,JO
h
NNY Doe,CEO
\L
标志 当在 replacement-string
中使用
\l
标志时,它会把后面所有的字符都当做小写字符来处理。
下面的例子,在 replacement-string 中的 H 前面放置了\L 标志,它会把 H 和它后面的所有字符
都换成小写:
$ sed -n 's/John/JO\LHNNY/p' employee.txt
101,JO
hnny
Doe,CEO
\u
标志 和\l
类似,只不过是把字符换成大写。当在
replacement-string
中使用
\u
标志时,它会把紧 跟在其后面的字符当做大写字符来处理。
下面的例子中,replacement-string 里面的 h 前面有 \u 标志,所以 h 将被换成大写的 H:
$ sed -n 's/John/jo\uhnny/p' employee.txt
101,jo
H
nny Doe,CEO
\U
标志 当在 replacement-string
中使用
\U
标志时,它会把后面所有的字符都当做大写字符来处理。
下面的例子中,replacement-string 里面的 h 前面有\U 标志,所以 h 及其以后的所有字符,
都将被换成大写:
$ sed -n 's/John/jo\Uhnny/p' employee.txt
101,jo
HNNY
Doe,CEO
\E
标志
\E 标志需要和\U 或\L 一起使用,它将关闭\U 或\L 的功能。
下面的例子将把字符串”Johnny Boy”
的每个字符都以大写的形式打印出来,因为在 replacement-string 前面使用了\U 标志:
$ sed -n 's/John/\UJohnny Boy/p' employee.txt
101,
JOHNNY BOY
Doe,CEO
下面将把
John
换成
JOHNNY Boy:
$ sed -n 's/John/\UJohnny\E Boy/p' employee.txt
101,
JOHNNY Boy
Doe,CEO
这个例子只把
Johnny
显示为大写,因为在
Johnny
后面使用了
\E
标志
(
关闭了
\U
的功能
)
替换标志的用法
上面的例子仅仅展示了这些标志的用法和功能。然而,如果你使用的是具体的字符串,那么
这些选项未必有什么作用,因为你可以在需要的地方写出精确的字符串,而不需要使用这些
标志进行转换。
和分组配合使用时,这些选项就显得很有用了。前面例子中我们已经学会了如何使用分组调
换第一列和第三列的位置。使用上述标志,可以把整个分组转换为小写或大写。
下面的例子,雇员 ID 都显示为大写,职位都显示为小写:
$ sed 's/\([^,]*\),\([^,]*\),\([^,]*\)/\U\2\E,\1,\L\3/' employee.txt
JOHN DOE,101,ceo
JASON SMITH,102,it manager
RAJ REDDY,103,sysadmin
ANAND RAM,104,developer
JANE MILLER,105,sales manager
这个例子中:
z
\U\2\E
把第二个分组转换为大写,然后用
\E
关闭转换
z
\L\3
把第三个分组转换为小写
资料来源于《SedandAwk101Hacks》,大家有兴趣可以买一本,也可以关注我,我更新完它。
曾经,我花费大半月将它们跑完,现在啥都忘了,还是要常用。
本文只交流学习,不为获利,侵权联系立删。