sed 学习

来源:互联网 发布:shell脚本编程大全 编辑:程序博客网 时间:2024/05/22 14:12

一. 替换

1.神奇变换(y命令的使用)


CODE:[Copy to clipboard]sed 'y/ori_letter_list/target_letter_list/' filename

 

CODE:[Copy to clipboard]cat filename
1234567890
2345678901
3456789012
4567890123
测试
将文件中1换成A
将文件中2换成B
...
将文件中0换成J


CODE:[Copy to clipboard]sed 'y/1234567890/ABCDEFGHIJ/' filename
ABCDEFGHIJ
BCDEFGHIJA
CDEFGHIJAB
DEFGHIJABC
注意变换关系是按两个list的位置对应变换,y是一个管局命令,拒绝使用后缀flag/g
list1:1234567890
list2:ABCDEFGHIJ
下面再作一个与前例相反的变换


CODE:[Copy to clipboard]sed 'y/0987654321/ABCDEFGHIJ/' filename
JIHGFEDCBA
IHGFEDCBAJ
HGFEDCBAJI
GFEDCBAJIH
2.替换每行第一个匹配


CODE:[Copy to clipboard]sed 's/regexpr/anyword/' filename
sed 's/regexpr/anyword/1' filename
举例:


QUOTE:
cat filename
1234567890 2345678901
3456789012 4567890123
sed 's/5/五/' filename
1234五67890 2345678901
34五6789012 4567890123
3.替换每行第n(如果有的话)个匹配


CODE:[Copy to clipboard]sed "s/regexpr/anyword/${n}" filename
cat filename
111111111111111111
222222222222222222
333333333333333333
444444444444444444
举例
sed "s/4/ 四 /8" filename
111111111111111111
222222222222222222
333333333333333333
4444444 四 4444444444
4.替换每行所有匹配


CODE:[Copy to clipboard]cat filename
1234567890 2345678901
3456789012 4567890123

 

CODE:[Copy to clipboard]举例:
sed 's/3/三/g' filename
12三4567890 2三45678901
三456789012 456789012三
二.行号处理

1.为文件加行号


CODE:[Copy to clipboard]sed = filename|sed 'N;s//n/:/'
cat filename
111111111111111111
222222222222222222
333333333333333333
444444444444444444
举例


CODE:[Copy to clipboard]sed = filename|sed 'N;s//n/:/' filename
1:111111111111111111
2:222222222222222222
3:333333333333333333
4:444444444444444444
2.仅为文件中的正文行加行号


CODE:[Copy to clipboard]sed /./= a|sed '/./N;s//n/:/'
举例


CODE:[Copy to clipboard]cat filename
111111111111111111

222222222222222222
333333333333333333

444444444444444444

sed /./= a|sed '/./N;s//n/:/' filename
1:111111111111111111

3:222222222222222222
4:333333333333333333

6:444444444444444444
三.字串翻转


CODE:[Copy to clipboard]sed '//n/!G;s//(./)/(.*/n/)/&/2/1/;//D;s/.//'
举例


CODE:[Copy to clipboard]echo 1234567890|sed '//n/!G;s//(./)/(.*/n/)/&/2/1/;//D;s/.//'
0987654321
四.选择性输出

1.打印文档奇数行(隔行输出)


CODE:[Copy to clipboard]sed 'n;d'
sed 'x;$!N;x'
sed -n 'p;n'

1
3
5
7
2.打印偶数行(隔行输出)


CODE:[Copy to clipboard]sed -n 'n;p'
sed '1d;n;d;'
2
4
6
8
3.删除连续重复行(大量使用了pattern space 文件太大时要注意)


CODE:[Copy to clipboard]sed '$!N; /^/(.*/)/n/1$/!P; D'    
#使用 $!N 要当心内存溢出
举例


CODE:[Copy to clipboard]cat file
111111111111111111
222222222222222222
222222222222222222
333333333333333333
444444444444444444
444444444444444444
444444444444444444
444444444444444444
444444444444444444

sed '$!N; /^/(.*/)/n/1$/!P; D' filename
111111111111111111
222222222222222222
333333333333333333
444444444444444444
4.合并上下行并以空格相分隔


CODE:[Copy to clipboard]sed '$!N;s//n/ /'
举例


CODE:[Copy to clipboard]cat file
1234567890
0987654321
执行命令后
1234567890 0987654321
5.将以/符号结尾的行与下行合并并以空格分隔(拼接断行)


CODE:[Copy to clipboard]sed -e :a -e '///$/N; s////n/ /; ta'
举例


CODE:[Copy to clipboard]cat filename
1 111111111111111111/
2 222222222222222222
3 333333333333333333/
4 444444444444444444

sed -e :a -e '///$/N; s////n/ /; ta' filename
1 111111111111111111 2 222222222222222222
3 333333333333333333 4 444444444444444444
6.按关键字拼接行
  如果某行以=开始,则合并到上一行并替代=为空格


CODE:[Copy to clipboard]sed -e :a -e '$!N;s//n=/ /;ta' -e 'P;D'
举例


CODE:[Copy to clipboard]cat file
111111111111111111
222222222222222222
=333333333333333333
444444444444444444

sed -e :a -e '$!N;s//n=/ /;ta' -e 'P;D' filename
111111111111111111
222222222222222222 333333333333333333
444444444444444444
7.输出匹配行的下一行


CODE:[Copy to clipboard]sed -n '/regexpr/{n;p;}' filename
举例


CODE:[Copy to clipboard]cat filename
1 111111111111111111
2 222222222222222222
3 333333333333333333
4 444444444444444444

sed -n '/^3/{n;p;}' filename
4 444444444444444444
8.显示匹配行的行号并输出匹配行的上行、匹配行、下行

sed -n -e '/regexpr/{=;x;1!p;g;$!N;p;D;}' -e h
举例


CODE:[Copy to clipboard]cat filename
1 111111111111111111
2 222222222222222222
3 333333333333333333
4 444444444444444444

sed -n -e '/^3/{=;x;1!p;g;$!N;p;D;}' -e h  filename
3                                       #匹配行的行号
2 222222222222222222  #上一行
3 333333333333333333  #匹配行
4 444444444444444444  #下一行
9.删除文档中某标志区域内的关键字匹配行

     删除文档中从being开到end结束的块中包含myword的行


CODE:[Copy to clipboard]sed '/^begin/,/^end/{/myword/d;}' filename

 

QUOTE:
cat filename
myword
begin
myword
Number!
myword
Number!
myword
Number!
myword
Number!
end
myword
Number!
测试


QUOTE:
myword
begin
Number!
Number!
Number!
Number!
end
myword
Number!
五.字串解析

1.从字串中解析出两个子串(前2各字符和后9个字符)


CODE:[Copy to clipboard]echo "WeLoveChinaUnix"|sed -e 'H;s//(../).*//1/;x;s/.*/(./{9/}/)$//1/;x;G;s//n/ /'
We ChinaUnix
2.分解日期串


CODE:[Copy to clipboard]echo 20030922|sed 's//(..../)/(../)/(../)//1 /2 /3/'|read year month day
echo $year $month $day
2003 09 22

先说说b吧:
比如有文件如下:


CODE:[Copy to clipboard]cat filename
a1234567890
1234567890
1234567890a
1234567890
123456a7890
先要求将其中的"5"替换成" 伍十万 ",但当该行包含字母"a"时,"5"就要替换成" 叁佰万 ".
现看如何通过b来实现:


QUOTE:
cat filename.sed
#!/bin/sed  -f
/a/b 5t             #如果当前行包含字母"a"则转到label"5t"处
s/5/ 五十万 /g   #将5替换成" 五十万 "
b                      #未指明跳转位置时,跳到Script的尾部
:5t                    #设置名称为"5t"的label
s/5/ 叁佰万 /g    #提换5为" 叁佰万 "
测试:


QUOTE:
sed -f filename.sed filename
1234 五十万 67890
a1234 叁佰万 67890
1234 五十万 67890
1234 叁佰万 67890a
1234 五十万 67890
1234 叁佰万 6a7890


                    The  Part II

小弟在sed使用中,对正则表达式有几个地方犯迷糊,为了彻底弄明白,试验之……
特将结果呈与各位,请师兄们批评指正!也让初学者少走弯路。
虽说有些问题在明白之后,感觉很简单,贴出来好像没必要;但在明白之前,的确很让人糊涂,所以还是决定贴出来。

In basic regular expressions the metacharacters ?, +, {, |,  (,  and  ) lose  their  special  meaning; instead use the backslashed versions /?, /+, /{, /|, /(, and /).
---以上来自man grep 中的REGULAR EXPRESSIONS

正则表达式中的限定符:
*        匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+        匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
?        匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n}        n是一个非负整数。匹配确定的n次。例如,'o{2}' 不能匹配"Bob"中的'o',但是能匹配"food"中的两个o。
{n,}        n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。
{n,m}        m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

/d        匹配一个数字字符。等价于 [0-9]。
/D        匹配一个非数字字符。等价于 [^0-9]。
/w        匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
/W        匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。


PS:linux 9 +sed-4.0.5-1
$ cat text
1*
1+
1?
1.
^1
1$
1{}
1{0,}
1{1,}
1{1,10}
1()
1[]
1[a-z]
1[^a-z]
1[a-z$]
1111
222222
1a
1bb
1//
aaa aa aa
boy/gire/people
boy3gire5people
boy4gire9people
x|y
aab|cddd
212
21/
t/w
t/W
y/d
y/D

$ cat text |sed -n '/1*/p'
将显示text所有内容,因为sed能直接识别正则表达式符号 * ,/1*/ 意思是与包括1和不包括1的所有行匹配。

$ cat text |sed -n '/1/*/p'
仅显示 1* 这一行, * 在转义之后只是一个普通字符。

$ cat text |sed -n '/1+/p'
仅显示 1+ 这行,因为sed并不能直接识别 + ,只是把它当作一个普通字符。

$ cat text |sed -n '/1/+/p'
显示所有含一个及以上 1 的行, + 在转义后,成为正则表达式。

$ cat text |sed -n '/1?/p'
仅显示 1?  这行,因为sed并不能直接识别正则表达式符合 ? ,只是把它当作一个普通字符。

$ cat text |sed -n '/1/?/p'
显示所有的行,/1/?/ 与包括1和不包括1的所有行均匹配。

$ cat text |sed -n '/1./p'
显示所有含1的行,因为sed能直接识别正则表达式符号“ . ” 。

$ cat text |sed -n '/1/./p'
仅显示匹配 1.  的这行,“ . ”在转义后仅是一普通字符。

$ cat text |sed -n '/^1/p'
显示所有以 1 开头的行,因为sed能直接识别正则表达式符合 ^ 。

$ cat text |sed -n '//^1/p'
显示 ^1 这一行, ^ 在转义后仅是一普通字符。

$ cat text |sed -n '/1$/p'
显示所有以 1 结尾的行,因为sed能直接识别正则表达式符号 $ 。

$ cat text |sed -n '/1/$/p'
显示 1$ 这一行, $ 在转义后仅是一普通字符。

$ cat text |sed -n '/1{}/p'
仅显示 1{} 这一行,因为sed并不能直接识别正则表达式符合{}。
$ cat text |sed -n '/1{1,}/p'
原理同上
$ cat text |sed -n '/1{1,10}/p'
原理同上
$ cat text |sed -n '/1{0,}/p'
原理同上
$ cat text |sed -n '/1()/p'
原理同上

$ cat text |sed -n '/1/{2,/}/p'
在转义之后,{} 在sed中具有 正则表达式限定符 功能,故显示两个及以上 1 的行。
$ cat text |sed -n '/1/{0,/}/p'
原理同上,显示所有含1及不含1 的行。

$ cat text |sed -n '/1[]/p'
报错“sed: -e expression #1, char 6: Unterminated address regex”,因为sed能直接识别正则表达式符号 [] ,但 [] 中间却为空,没有相关集合(字母或数字),故错。

$ cat text |sed -n '/1/[/]/p'
显示 1[] 这一行, []在转义后仅是普通字符。

$ cat text |sed -n '/1[0-9]/p'
1{1,10}
1111
不过我不明白为何会跑出第一行?难道是我的机器有毛病???因为/1[0-9]/与{1,10}中的 “10”匹配!

$ cat text |sed -n '/1[^0-9]/p'
显示出所有含1 ,并且 1 后面非数字的行。

$ cat text |sed -n '/boy/gire/people/p'
无显示。因为sed不知道 /g /p 是什么,找不到匹配的东东! :D

$ cat text |sed -n '/boy//gire//people/p'
显示包含 boy/gire/people 的这一行,第一个/ 把紧随的 / 转义成普通字符。

$ cat text |sed -n '/boy[0-9]/p'
boy3gire5people
boy4gire9people

但是
$ cat text |sed -n '/boy/d/p'
$ cat text |sed -n '/boy/d/{1/}/p'
却都没有显示,/d 不是等价于 [0-9] 。这里为甚么没显示?
/d /D /w /W 在使用时我还没有找到窍门,还请各位指教!
本人测试后,发现:
/w  在sed中好像只等价于'[A-Za-z_]'
/W 在sed中好像只等价于'[^A-Za-z_]'
/d  在sed中等价于'd'
/D  在sed中等价于'D'
/s 在sed中等价于's'
/S 在sed中等价于'S'

$ cat text |sed -n '/b|c/p'
显示 aab|cddd 这一行。sed把 | 当作普通字符。
$ cat text |sed -n '/x|y/p'
显示 x|y 这一行。sed把 | 当作普通字符。

$ cat text |sed -n '/aab/|212/p'
aab|cddd
212
|在转义之后表示 “或”的功能,对匹配aab 或 212 的行进行显示。

小结:
sed中可直接使用的RE:
*  .  ^  $  [  ]  /  c
/w ( 相当于[A-Za-z_] )  /W ( 相当于[^A-Za-z_] )
sed中需转义使用的RE:
+  ?  {  }  (  )  |  <  >
其他:
/d (d)  /D (D)  /s (s)  /S (S)
匹配 单引号’ 用双引号
匹配 反引号` 用单引号
/b 匹配单词的前或后边界 ( 字符[^A-Za-z0-9_]均构成单词边界 )
/B 匹配单词的非边界 ( 字符[^A-Za-z0-9_]均构成单词边界 )
/< 匹配单词的位置前 ( 字符[^A-Za-z0-9_]均构成单词边界 )
/> 匹配单词的位置后 ( 字符[^A-Za-z0-9_]均构成单词边界 )
支持十进制,格式为“/d + 两位或三位十进制数”,如“/d065 或/d65 均代表字符 A ”
支持十六进制,格式为“/x + 两位十六进制数”,如“/x61 代表字符 A ”
支持八进制,格式为“/o + 两位或三位八进制数”,如“/o077 或/o77 均代表字符 ?,/o101代表字符 A ”

sed和awk只支持下列转义字符
/y, /B, /<, />, /w, /W, /`, and /'
详情请看man awk

对于 sed 4.0.5

1. 没有 /D

2. 没有 /d, 只有 /dXXX.  例如 /d097 也就是字符  a

3.  /W, /w, /S, /s  没有正常工作, 这是 4.0.5 的 bug# 09022.
可能在 sed-4.0.7-2 中解决。

题外话: 各位用 GNU 工具多了,也有不好的地方,那就是 GNU 扩展太多,
与其他平台不兼容, 不利于跨平台使用。

$ cat text |sed -n '/1*/p'
将显示text所有内容,因为sed能直接识别正则表达式符号 * ,/1*/ 意思是与包括1和不包括1的所有行匹配。
*的意思是 0个或多个,所以有 1 和没1 的均显示。