文本处理工具sed是一个很强大的工具,感谢zooyo大哥的帮助(http://zooyo.blog.chinaunix.net)的指导,同时建议大家看看awk与sed这本书,本来打算传份电子版的上来的,但是有人传过了,不让传了,那就这样吧!
sed还有一个调试工具叫sedsed,按上这个工具,sed命令执行过程你就会一清二楚,在最后会给出安装过程以及使用方式。
sed的命令的使用方式:
1> 删除显示
sed  'n1d'  filename   显示file除了第n1行
sed  'n1,n2' filename  显示file除了第n1 到n2行
sed '10,20d' filename  显示file除了第10到20行间内容。
sed  '5,$d' filename   显示file除了前四行间内容。
命令"d"作用是删除模式空间的内容,然后读入新的行,sed脚本从头再次开始执行。而命令"D"的不同之处在于它删除的是直到第一个内嵌换行符为止的模式空间的一部分,但是不会读入新的行,脚本将回到开始对剩下内容进行处理。
看下面例子:
 

# cat 14.txt
This line is followed by 1 blank line.

This line is followed by 2 blank line.


This line is followed by 3 blank line.



This line is followed by 4 blank line.




This is the end.

# sed '/^$/{N;/^\n$/D}' 14.txt
This line is followed by 1 blank line.

This line is followed by 2 blank line.

This line is followed by 3 blank line.

This line is followed by 4 blank line.

This is the end.
# sed '/^$/{N;/^\n$/d}' 14.txt
This line is followed by 1 blank line.

This line is followed by 2 blank line.
This line is followed by 3 blank line.

This line is followed by 4 blank line.
This is the end.
(如果上面例子看不懂,看到最后再返回来看)

2>替换
sed 's/string1/string2/' filename             将替换每行第一个匹配string1换成string2
sed 's/string1/string2/n' filename            将替换每行第n次出现的string1换成string2
sed 's/string1/string2/g' filename            将替换每行所有匹配string1换成string2
sed 'y/string_list1/string_list2/' filename   将string_list1的字段用string_list2对应字段替换,作用和tr命令相同。

3>追击,插入和更改。
a\ 命令是追加命令,追加将添加新文本到文件中当前行(即读入模式缓冲区中的行)的后面。所追加的文本行位于sed命令的下方另起一行。如果要追加的内容超过一行,则每一行都必须以反斜线结束,最后一行除外。最后一行将以引号和文件名结束。
i\ 命令是在当前行的前面插入新的文本。
c\ 用新的文本改变本行的文本
 

#cat gaby
111111111111111111

222222222222222222

333333333333333333

444444444444444444

# sed '/^1.*1$/a\gaby\ngabylinux' gaby
111111111111111111
gaby
gabylinux

222222222222222222

333333333333333333

444444444444444444
# sed '/^1.*1$/i\gaby\ngabylinux' gaby
gaby
gabylinux
111111111111111111

222222222222222222

333333333333333333

444444444444444444
# sed '/^1.*1$/c\gabylinux' gaby
gabylinux

222222222222222222

333333333333333333

444444444444444444

4>匹配范围操作{}
# sed  '/^1.*1$/,/^4.4*$/{s/^$//;s/3/9/}' gaby
111111111111111111

222222222222222222

933333333333333333

444444444444444444

5>打印匹配行号
# sed  -n '/1111111/=' gaby
1
# sed  -n '/1111111/{=;p}' gaby
1
111111111111111111

6>下一行操作
n  
读取下一个输入行,用下一个命令处理新的行而不是用第一个命令。  
N  
追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。

多行Next(N)命令是相对于next(n)命令的,后者将模式空间中的内容输出,然后把下一行读入模式空间,但是脚本并不会转移到开始而是从当前的n 命令之后开始执行;而前者则保存原来模式空间中的内容,再把新的一行读入,两者之间依靠一个换行符"\n"来分隔。在N命令执行后,控制流将继续用N命令以后的命令对模式空间进行处理。
值得注意的是,在多行模式中,特殊字符"^"和"$"匹配的是模式空间的最开始与最末尾,而不是内嵌"\n"的开始与末尾。


用awk and sed书中的例子可以很好说明N和n的区别
 

# cat 11.txt
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
available on your system.
现在要将"Owner and Operator Guide"替换为"Installation Guide":

# sed '/Operator$/{N;s/Owner and Operator\nGuide /Installation Guide\n/}' 11.txt
Consult Section 3.1 in the Installation Guide
for a description of the tape drives
available on your system.
# sed '/Operator$/{n;s/Owner and Operator\nGuide /Installation Guide\n/}' 11.txt
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
available on your system.
 

# cat 12.txt
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
available on your system.

Look in the Owner and Operator Guide shipped with your system.

Two manuals are provided including the Owner and
Operator Guide and the User Guide.

The Owner and Operator Guide is shipped with your system.

现在要将"Owner and Operator Guide"替换为"Installation Guide":
# sed 's/Owner and Operator Guide/Installation Guide/;/Owner/{N;s/ *\n/ /;s/Owner and Operator Guide */Installation Guide/}' 12.txt
Consult Section 3.1 in the Installation Guidefor a description of the tape drives
available on your system.

Look in the Installation Guide shipped with your system.

Two manuals are provided including the Installation Guideand the User Guide.

The Installation Guide is shipped with your system.

上面命令s/Owner and Operator Guide/Installation Guide/;是必要的,如果不想要可以换成如下($!N)
# sed '/Owner/{$!N;s/ *\n/ /;s/Owner and Operator Guide/Installation Guide/}' 12.txt

7> 读取(r)和写入命令(w)
# sed '/1111/r /root/gaby' gaby
111111111111111111
111111111111111111

222222222222222222

333333333333333333

444444444444444444


222222222222222222

333333333333333333

444444444444444444
#sed -n '/^$/d;/1111/w a.txt' gaby
# cat a.txt
111111111111111111

8>提取奇偶行
奇数行
# sed '/^$/d' gaby | sed 'n;d'
111111111111111111
333333333333333333
# sed  '/^$/d' gaby | sed -n 'p;n'
111111111111111111
333333333333333333
# sed  '/^$/d' gaby | sed  'x;$!N;x'
111111111111111111
333333333333333333
偶数行
# sed '/^$/d' gaby | sed -n 'n;p'
222222222222222222
444444444444444444
# sed  '/^$/d' gaby | sed '1d;n;d'
222222222222222222
444444444444444444

9>合并重复行相当于uniq,命令如下。
sed '$!N; /^\(.*\)\n\1$/!P; D' filename

10> 高级流控制

 

b 分支:无条件转移
t 测试:有条件的转移
它们将脚本中的控制转移到包含特殊标签的行;如果没有标签则直接转移到脚本的末尾。只有当替换命令改变当前行时才会被执行。
直接上例子:
#cat file:
a b c a d a
s d d d x s a
h j s a s h j h
j d f j a s j k j
要求:删除行内与第一列字符重复的字符,shell、sed、awk各写一个。达到这个结果:
a b c d
s d d d x a
h j s a s j
j d f a s k
这个例子来自
http://blog.chinaunix.net/uid-10540984-id-3086644.html
给出了三种解决办法
while read a b;do echo "$a ${b// $a}";done <file
awk '{a=$1;gsub(" ?"a,"");print a""$0}' file
sed ':a;s/^\(.\)\(.*\) \1/\1\2/;ta' file

cat file
c-h-i-n-a -unix

我只想替换空格前面的字符中的 "-" 符号:
china -unix
sed -r ':a;s/-(.* .*)/\1/;ta' file

把字符串 01/02/03/t1.txt 拆分成 01,01/02,01/02/03,01/02/03/t1.txt
sed ':1 s#^\([^,]\+\)/\(.*\)#\1,\1/\2#;t1

 
sed -n '/send/{:a;N;/back/{/KEYWORD/p;b};ba}' 1.log
上面这个是搜索senddata,然后建标签a并且开始搜索下面行,查到costTime后执行{}里面的语句,查找keyword,然后跳转到ba处,然后ba跳转到标签a,这样是成功的取到send与back之间包含keyword的行。
如果你看不懂上面几个例子:建议到链接去看,也可以去看看下面的转帖:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=605565

sedsed的工具
wget http://aurelio.net/sedsed/sedsed-1.0
touch /usr/local/bin/sedsed
cat sedsed-1.0 >> /usr/local/bin/sedsed
chmod 755 /usr/local/bin/sedsed
使用方法: http://sedsed.sourceforge.net/
上有使用方法,还比较全,等以后我使用的时候再贴上来。

eg1:
 

需要添加nginx 301跳转
域名很多,想用sed搞定
server {
        listen             80;
        server_name    www.aa.com ;
        access_log    off;
        location / {
                root     /www/aa;
                index    index.html index.htm index.php;
        }
        location ~ \.php$ {
                root                     /www/aa;
                fastcgi_pass     127.0.0.1:9000;
                fastcgi_index    index.php;
                fastcgi_param    SCRIPT_FILENAME    /www/aa$fastcgi_script_name;
                include                fastcgi_params;
                fastcgi_param    DOCUMENT_ROOT /www/aa;
                fastcgi_param    HOSTNAME www.aa.com;
        }
}
有很多这样的server 段,现在想把aa.com自 动跳转到 www.aa.com
server_name    www.aa.com    aa.com;
if ($host != 'www.aa.com' ) {
rewrite ^/(.*)$ http://www.aa.com/$1 permanent;
}
sed -r 's#(server_name\s+www\.)(.*)\s;#\1\2\2;\n\tif($host != "wwww.\2")\n\t{ \n\t\trewrite ^/(.*)$ http: //www.\2 last;\n\t} #g' nginx.conf


eg2
cat dhcp.conf
 

ddns-update-style interim;
ignore client-updates;
default-lease-time 21600;
max-lease-time 43200;

subnet 192.168.10.0 netmask 255.255.255.0 {
        option subnet-mask                            255.255.255.0;
             option routers                                    192.168.10.121;
        range dynamic-bootp 192.168.10.1 192.168.10.101;
        host vm01 {
             hardware ethernet 00:00:00:00:30:00;
             fixed-address 192.168.10.101;
            }
}

subnet 192.168.10.0 netmask 255.255.255.0 {
        option subnet-mask                            255.255.255.0;
        option routers                                    192.168.10.129;
        range dynamic-bootp 192.168.10.102 192.168.10.254;
             host vm02 {
                         hardware ethernet 00:00:00:00:01:00;
                         fixed-address 192.168.10.104;
                 }
}

现在又一个需求,我想通过mac地址 修改上面option routers     后面的ip地址:
 

sed '/^subnet/{:1;N;/\n}/!b1;/hardware ethernet 00:00:00:00:01:00/s/\(option routers\s*\)[^;]*/\1111.111.111.111/}' dhcpd.conf

这运用了sed的多行处理和高级流控制。还可以用shell,虽然比较复杂点但是 好理解。大致思路就是用grep ,找出需要修改的行号,然后用sed对那行处理。
 

grep -n -B 3 " 00:00:00:00:01:00" dhcpd.conf    | grep    'option routers' | cut -d- -f1

比如是第18行

sed -i '18,18 s#option routers.*#option routers     192.168.10.100#g' dhcpd.conf