nginx反向代理缓存配置

这里给出示例,并详解。

  1. http {
  2. […]
  3. […]
  4.  
  5. proxy_cache_path  /data/nginx/cache/one  levels=1:2   keys_zone=one:10m max_size=10g;
  6. proxy_cache_key  "$host$request_uri";
  7.  
  8. server {
  9.     server_name devops.webres.wang webres.wang;
  10.     root /home/devops.webres.wang/web;
  11.     index index.php index.html index.htm;
  12.     location / {
  13.         proxy_pass http://127.0.0.1:8080;
  14.         proxy_set_header  Host "devops.webres.wang";
  15.         proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  16.         #开启反向代理缓存,并使用zone name为one的缓存。
  17.         proxy_cache one;
  18.         #设置状态码为200 302过期时间为10分钟
  19.         proxy_cache_valid  200 302  10m;
  20.         #设置状态码404的过期时间为1分钟
  21.         proxy_cache_valid  404      1m;
  22.     }
  23.     #清除缓存
  24.     location ~ /purge(/.*) {
  25.         #允许的IP
  26.         allow 127.0.0.1;
  27.         deny all;
  28.         proxy_cache_purge one $host$1$is_args$args;
  29.     }
  30. }
  31.  
  32. }

反向代理的缓存主要涉及以下几个命令:
proxy_cache_path proxy_cache_key proxy_cache proxy_cache_valid。

proxy_cache_path
这个是设置缓存的目录,语法如下:
proxy_cache_path path [ levels = levels ] keys_zone = name : size [ inactive = time ] [ max_size = size ] [ loader_files = number ] [ loader_sleep = time ] [ loader_threshold = time ]
可放置的上下文:
http
参数解释:
[ levels = levels ]:
设置缓存目录层数,如levels=1:2,表示创建两层目录缓存,最多创建三层。第一层目录名取proxy_cache_key md5的最后一个字符,第二层目录名取倒数2-3字符,如:
proxy_cache_key md5为b7f54b2df7773722d382f4809d65029c,则:
levels=1:2为/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c
levels=1:2:3为/data/nginx/cache/c/29/650/b7f54b2df7773722d382f4809d65029c

keys_zone = name : size:
定义缓存区域名称及大小,缓存名称用于proxy_cache指令设置缓存放置在哪,如proxy_cache one,则把缓存放在zone名称为one的缓存区,即proxy_cache_path指定的具体位置。

proxy_cache_key
这个指令是设置以什么参数md5得到缓存的文件名,默认为$scheme$proxy_host$request_uri,即以协议、主机名、请求uri(包含参数)作md5得出缓存的文件名。
proxy_cache_key与下面的清缓存功能(purge cache)有很大关系。
可放置在上下文,http server location

proxy_cache
反向代理缓存设置指令,语法proxy_cache zone | off,默认为off。上下文:http server location。
可以放到指定location,这样匹配此location的url才被缓存。

proxy_cache_valid
设置指定状态码的缓存时间,语法proxy_cache_valid [ code …] time。

另外,清缓存需要安装插件ngx_cache_purge,安装方法如下:

  1. cd /tmp
  2. wget http://labs.frickle.com/files/ngx_cache_purge-2.1.tar.gz
  3. tar xzf ngx_cache_purge-2.1.tar.gz
  4. cd /tmp
  5. wget http://nginx.org/download/nginx-1.4.2.tar.gz
  6. tar xzf nginx-1.4.2.tar.gz
  7. cd nginx-1.4.2
  8. ./configure –prefix=/usr/local/nginx  –add-module=/tmp/ngx_cache_purge-2.1
  9. make && make install

参考:
http://wiki.nginx.org/HttpProxyModule
http://labs.frickle.com/nginx_ngx_cache_purge/

EZHTTP — LAMP,LNMP,LNAMP一键安装

EZHTTP简介

EZHTTP是集成了nginx apache php mysql memcached等web服务器软件的一键安装脚本(支持lnmp,lanmp,lanmp),它能自由选择安装任意的软件,自动选最优线路下载,定制容易。更详细的介绍请转到:devops.webres.wang/ezhttp/。下面详细介绍下如何使用(附:EZHTTP QQ群:153447657)。

如何安装

因为安装时间会比较久,建议安装前使用screen,screen使用方法如下:
1、首先得安装screen,ubuntu使用apt-get install screen,centos或redhat使用yum install screen安装
2、创建一个ezhttp的会话,screen -S ezhttp
3、如果终端意外断开,则可以使用screen -r ezhttp恢复

  1. screen -S ezhttp
  2. wget –no-check-certificate https://github.com/centos-bz/EZHTTP/archive/master.zip -O EZHTTP.zip
  3. unzip EZHTTP.zip
  4. cd EZHTTP-master
  5. chmod +x start.sh
  6. ./start.sh

执行start.sh脚本后,会出现如下界面:
Web服务器
这里分了两种安装方式:
第一种是快速安装,即直接读取安装包下的config文件,config文件也是一个bash脚本,脚本里预定义了安装什么软件,以及安装的路径,大家可以自行修改里面的参数而使下次可以快速安装,config脚本部分截图:
Web服务器
第二种是高级设置,即全部参数都需要自己定义,我们这里输入2继续安装:
Web服务器
首先是nginx的安装设置,这里有三个版本选择1) nginx-1.4.1 2) tengine-1.4.6 3) ngx_openresty-1.2.8.3,当然你也可以选择不安装,即4) do_not_install。 这里我们选择1继续:
Web服务器
选择1后,需要我们定义nginx安装的路径,如果直接回车,默认路径为/usr/local/nginx,当然你也可以输入自己安装的路径,比如/home/nginx,我们这里直接回车:
Web服务器
到了apache安装的设置,有两个版本可选1) httpd-2.2.25 2) httpd-2.4.4,这里建议选择2.4版本的安装,性能会好于2.2:
Web服务器
同样需要设置安装路径,默认是/usr/local/apache。
Web服务器
到了mysql的安装设置,有三个版本可选,以及mysqlclient的库安装,1) mysql-5.1.71 2) mysql-5.5.32 3) mysql-5.6.12 4) libmysqlclient18
1,2,3是版本的选择安装,而4是只安装mysqlclient的库,而不安装完成的mysql server,当你有独立的数据库服务器,而只想安装php连接这台独立的数据库服务器时,又不想在web服务器上安装整个mysql数据库,可以只选择安装libmysqlclient18,这将节省大量的安装时间。这里我们选3安装:
Web服务器
设置mysql的安装位置,默认/usr/local/mysql。我们这里直接回车。
Web服务器
设置mysql数据文件的安装位置,默认是安装在mysql安装路径的子目录data,我们这里直接回车。
Web服务器
设置mysql root密码,默认是root:
Web服务器
到了php的安装设置,可选版本有1) php-5.2.17 2) php-5.3.26 3) php-5.4.16,这里推荐php5.3:
Web服务器
这里需要选择由什么来解析php脚本,有两种选择,一种with_apache,即使用apache的mod_php模式来解析,另一种是fastcgi来解析php,当你前面选择安装nginx时,建议选2,当你前面选择安装apache时,就选1。这里我们选择2,fastcgi解析php。
Web服务器
php安装路径,默认/usr/local/php。
Web服务器
这里是php模块的选择安装,模块的可选安装列表会根据你上面所选的php版本,因为我们上面选的php版本为php5.3.26,所以可选安装的模块有:1) ZendGuardLoader 2) eaccelerator-0.9.6.1 3) imagick-3.0.1 4) ioncube_loaders 5) memcache-3.0.8,而如何你的php版本为php5.2.17,ZendGuardLoader则会变成ZendOptimizer。可以多选安装,如输入1 2 3,则是安装ZendGuardLoader、eaccelerator和imagick。不需要全部安装,根据你php程序的需求即可,这里我们选择2 5:
Web服务器
这里是选择安装其它的软件,可选安装有1) memcached-1.4.15 2) pure-ftpd-1.0.36 3) phpMyAdmin-4.0.4-all-languages,可以多选,这里我们选择安装全部,1 2 3。
Web服务器
选择安装软件后,还需要设置安装的路径,这里都有默认的设置,memcached默认路径为/usr/local/memcached,pureftpd为/usr/local/pureftpd,phpmyadmin默认安装到nginx默认网站根目录,如果你使用的是apache,则需要修改,apache默认网站路径为/usr/local/apache/htdocs。
Web服务器
输入完phpmyadmin的安装路径后,会显示全部的设置信息,如果确认设置无误,输入y开始安装,如何确认有误,则可以输入n重新设置。
安装完成后,会显示所有正在监听的端口:
Web服务器
如看见80,3306端口以及/tmp/php-cgi.sock,表示nginx或者apache、mysql,php-fpm安装成功,即可通过域名或者ip访问默认首页,centos-6需要先关闭iptables或者开放80端口访问,如:
Web服务器

EZ命令使用

ez nginx add(添加nginx虚拟主机)
Web服务器
执行此命令后,提示输入需要绑定的域名,多个域名以空格分隔,如devops.webres.wang webres.wang。
Web服务器
接着要求输入网站目录,默认为/home/domain/web,日志路径为/home/domain/logs,所以如果你输入的网站目录为/home/centos,根目录其实是/home/centos/web,日志路径为/home/centos/logs。
Web服务器
接着会问是否添加伪静态规则,输入y进入规则列表,可选有1、DEDECMS 2、Discuz_7 3、Discuz_X 4、ECshop 5、PHPCMS 6、PHPWind 7、Shopex 8、Typecho 9、WordPress。输入对应的数字选择。
Web服务器
接着会询问是否需要支持php,如果nginx只是提供静态页面的访问,则输入n,否则y。
Web服务器
这样nginx虚拟主机就添加完成了。
ez nginx list(列出nginx虚拟主机)
Web服务器
执行此命令会马上列出所有的nginx虚拟主机,信息包括域名及根目录。
ez nginx del(删除nginx虚拟主机)
Web服务器
删除虚拟主机只需要输入对应的域名,删除之前会自动重载nginx配置文件,无需手动。
ez apache add(新增apache虚拟主机)
Web服务器
添加apache虚拟主机只需要输入域名及网站目录。
ez apache list(列出apache虚拟主机)
Web服务器
ez apache del(删除apache虚拟主机)
Web服务器
ez mysql add(添加mysql数据库或用户)
此命令是用来添加mysql数据库或者用户的,操作方法如下:
执行ez mysql add,会提示输入root用户密码:
下面按提示操作即可。
ez mysql del(删除mysql数据库或用户)
用来删除mysql数据库或者用户。
ez mysql mod(修改mysql用户密码)
用来修改mysql用户密码
ez mysql reset(重置mysql root密码)
当mysql root用户的密码忘记时,这个命令可以帮助你重置。

定制EZHTTP软件版本

我想要安装最新版本的软件,我们这里以mysql5.6为例:
现在EZHTTP mysql5.6系列的安装版本为mysql-5.6.12,而现在官网的最新版本为mysql-5.6.13,如何更新EZHTTP的为最新的呢?
需要修改两个文件:
第一个文件init:
我们打开安装包下的init文件,找到mysql5.6系列的设置:
Web服务器
我们看到mysql5.6设置分为三个:
一是mysql5_6_filename变量,这个是设置mysql5.6的文件名,如mysql-5.6.12,我们这里更改为mysql-5.6.13
二是mysql5_6_baidupan_link,这个是百度网盘的链接,你可以利用网盘的离线下载来下载mysql5.6.13并获取链接地址。如果不想使用网盘下载,可以设置为mysql5_6_baidupan_link=””,设置为空。
三是mysql5_6_official_link,这个是下载mysql5.6的直链,不一定要是官方的链接,可以是其它下载的直链。
第二个文件conf/md5.txt
最后一步是设置mysql5.6.13的md5信息到安装包下的conf/md5.txt文件。
在文件的任何一行添加:

  1. aff97b406da871f020af84b7085cbdbb  mysql-5.6.13.tar.gz

此md5需要用md5软件算出,linux下可以使用md5sum mysql-5.6.13.tar.gz得出。
完成这两步就完成了mysql5.6版本的升级,够简单吧。

Web压力测试工具-http_load

介绍个http_load压力测试工具,http_load,类似的工具还有webbench、ab、Siege。

1、下载

官方网站:http://acme.com/software/http_load/

  1. cd /root
  2. wget http://acme.com/software/http_load/http_load-12mar2006.tar.gz
  3. tar xzf http_load-12mar2006.tar.gz

2、安装

  1. cd http_load-12mar2006
  2. make

执行完make,会在当前目录生成一个http_load二进制文件。

3、使用方法

  1. root@www:~/http_load-12mar2006# ./http_load –help
  2. usage:  ./http_load [-checksum] [-throttle] [-proxy host:port] [-verbose] [-timeout secs] [-sip sip_file]
  3.             -parallel N | -rate N [-jitter]
  4.             -fetches N | -seconds N
  5.             url_file
  6. One start specifier, either -parallel or -rate, is required.
  7. One end specifier, either -fetches or -seconds, is required.

主要参数说明:
-parallel 简写-p :含义是并发的用户进程数。
-rate 简写-r :含义是每秒的访问频率
-fetches 简写-f :含义是总计的访问次数
-seconds简写-s :含义是总计的访问时间

选择参数时,-parallel和-rate选其中一个,-fetches和-seconds选其中一个。
示例:

  1. http_load -parallel 50 -s 10 urls.txt

这段命令行是同时使用50个进程,随机访问urls.txt中的网址列表,总共访问10秒。

  1. http_load -rate 50 -f 5000 urls.txt

每秒请求50次,总共请求5000次停止。

Bash Shell字符串操作小结

1. 取长度

  1. str="abcd"
  2. expr length $str   # 4
  3. echo ${#str}       # 4
  4. expr "$str" : ".*" # 4

好像一般使用第二种

2. 查找子串的位置

  1. str="abc"
  2. expr index $str "a"  # 1
  3. expr index $str "b"  # 2
  4. expr index $str "x"  # 0
  5. expr index $str ""   # 0

3. 选取子串

  1. str="abcdef"
  2. expr substr "$str" 1 3  # 从第一个位置开始取3个字符, abc
  3. expr substr "$str" 2 5  # 从第二个位置开始取5个字符, bcdef
  4. expr substr "$str" 4 5  # 从第四个位置开始取5个字符, def
  5. echo ${str:2}           # 从第二个位置开始提取字符串, bcdef
  6. echo ${str:2:3}         # 从第二个位置开始提取3个字符, bcd
  7. echo ${str:(-6):5}        # 从倒数第二个位置向左提取字符串, abcde
  8. echo ${str:(-4):3}      # 从倒数第二个位置向左提取6个字符, cde

4. 截取子串

  1. str="abbc,def,ghi,abcjkl"
  2. echo ${str#a*c}     # 输出,def,ghi,abcjkl  一个井号(#) 表示从左边截取掉最短的匹配 (这里把abbc字串去掉)
  3. echo ${str##a*c}    # 输出jkl,             两个井号(##) 表示从左边截取掉最长的匹配 (这里把abbc,def,ghi,abc字串去掉)
  4. echo ${str#"a*c"}   # 输出abbc,def,ghi,abcjkl 因为str中没有"a*c"子串
  5. echo ${str##"a*c"}  # 输出abbc,def,ghi,abcjkl 同理
  6. echo ${str#*a*c*}   # 空
  7. echo ${str##*a*c*}  # 空
  8. echo ${str#d*f)     # 输出abbc,def,ghi,abcjkl,
  9. echo ${str#*d*f}    # 输出,ghi,abcjkl 
  10. echo ${str%a*l}     # abbc,def,ghi  一个百分号(%)表示从右边截取最短的匹配
  11. echo ${str%%b*l}    # a             两个百分号表示(%%)表示从右边截取最长的匹配
  12. echo ${str%a*c}     # abbc,def,ghi,abcjkl

可以这样记忆, 井号(#)通常用于表示一个数字,它是放在前面的;百分号(%)卸载数字的后面; 或者这样记忆,在键盘布局中,井号(#)总是位于百分号(%)的左边(即前面) 🙂

5. 字符串替换

  1. str="apple, tree, apple tree"
  2. echo ${str/apple/APPLE}   # 替换第一次出现的apple
  3. echo ${str//apple/APPLE}  # 替换所有apple
  4. echo ${str/#apple/APPLE}  # 如果字符串str以apple开头,则用APPLE替换它
  5. echo ${str/%apple/APPLE}  # 如果字符串str以apple结尾,则用APPLE替换它

6. 比较

  1. [[ "a.txt" == a* ]]        # 逻辑真 (pattern matching)
  2. [[ "a.txt" =~ .*.txt ]]   # 逻辑真 (regex matching)
  3. [[ "abc" == "abc" ]]       # 逻辑真 (string comparision)
  4. [[ "11" < "2" ]]           # 逻辑真 (string comparision), 按ascii值比较

7. 连接

  1. s1="hello"
  2. s2="world"
  3. echo ${s1}${s2}   # 当然这样写 $s1$s2 也行,但最好加上大括号

转自:http://my.oschina.net/aiguozhe/blog/41557

使用sed对nginx配置文件进行删除和列出虚拟主机操作

带着需要使用sed来对nginx配置文件进行操作的强烈需求,于是开始了学习sed的高级应用。虽然之前也一直在用sed,但也只是接触到了s替换命令,其它高级的命令没用到,所以没有动力去学。一直觉得要学到点东西,前提是你现在有一问题,需要用到这个技术来解决,而且有强烈的渴望要把这个问题解决,这时候你学习这项技术会事半功倍。否则学习起来会非常的枯燥无味,效率低,甚至会放弃。下面是我最近学sed得出的成果,备忘一下,以防失忆。
一、列出所有虚拟的server_name和对应的root

  1. sed -n "
  2. /servers*{/{
  3. H
  4. :loop
  5. n;H
  6. /}/{
  7. s/}//;x;H
  8. s/.*server_names*([^;]*);.*/1/p
  9. x
  10. s/.*roots*([^;]*);.*/1/p
  11. s/.*//g;x
  12. }
  13. /{/!b loop
  14. :loop1
  15. n;H
  16. /}/!b loop1
  17. b loop
  18. }
  19. " nginx-devops.webres.wang.conf

二、删除指定server_name的虚拟主机

  1. domain="devops.webres.wang"
  2. sed -i -n "
  3. /servers*{/{
  4. H
  5. :loop
  6. n;H
  7. /}/{
  8. s/}//;x
  9. /.*server_names*$domain.*/d
  10. p;d
  11. }
  12. /{/!b loop
  13. :loop1
  14. n;H
  15. /}/!b loop1
  16. b loop
  17. }
  18. p
  19. " nginx-devops.webres.wang.conf

代码有点多,就不具体分析了,具体说下如何找出server {} 代码块。

代码分析:
1、首先先关闭自动打印功能,即-n选项,因为下面会用到n命令,会自动打印,所以添加-n之后,使用n命令就不会自动打印了,需要打印时,使用p命令。
2、匹配 server {,如果匹配到,则把pattern space的内容添加到hold space,然后进入loop循环,执行n命令(n命令不必进入新的循环读取下一步到pattern space),再用H附加到hold space
3、判断是否找到代码块结束符},如果找到,进入server {}代码块处理阶段,处理完之后,进入下一个循环,继续找出下一个server{}。
4、如果找不到,再判断是否找到{,如果没有找到,进入loop循环
5、如果找到了{,表示存在if {},或者location {},则必要找到两个}才算是完整的server代码块。此时进入loop1循环,n命令读取下一行,附加到hold space。
6、再判断是否找到},如果没有找到,继续loop1循环,如果找到了,还需要一个},所以跳到loop循环。
7、如此循环下来,直接找到完整的server代码块。

关键的几点提示:
1、n命令是直接清空pattern space,并读取下一行到pattern space,而不需要进入新的循环。在这里的作用是,因为要把pattern space的内容附加到hold space,所以每读取一行,必需先清空pattern space,然后再附加到hold space,这样hold space才不会出现重复内容。要达到清空pattern space,读取下一行,进入下一循环可以做到,但进入下一循环后,必需重新匹配server {,而下一行肯定无法匹配,所以就达不到累积的效果。
2、hold space在这里很重要,它的内容来自pattern space对其进行附加操作。累积到完整的server代码块时,再与pattern space进行交换,交换之前必需把pattern space清空,这样交换后,hold space才能为空,为累积出下一个server代码块做准备。
最后还是建议使用sed的debug工具sedsed查看pattern space和hold space的变化。http://aurelio.net/projects/sedsed/

sed高级应用示例

最近需要使用sed来解析nginx配置文件,而之前使用sed仅限制于对文件的替换及添加文本,不过也基本能满足平时的bash shell脚本的编写工作。但这次需要解析nginx配置文件来对虚拟主机的代码块进行处理,比如对指定虚拟主机的删除,以及列出所有虚拟主机的信息,比如根目录是哪个。单靠简单的匹配是无法满足这个需求了,于是重读了一遍http://www.gnu.org/software/sed/manual/sed.htmlsed的教程,开始渐渐懂得sed的工作原理以及如何使用sed的高级功能。在分析高级应用的例子之前,我们来了解下sed的工作原理,这至关重要。

sed工作原理

sed是一个流文本处理工具,从文件头到文件尾读取,一次只读取一行,并完成一系列操作才继续读取下一行。sed维护两个数据缓冲区,一个是pattern space,一个是hold space。它们初始都为空。pattern space是活跃缓冲区,每一次循环都会清空再存入下一行内容。hold space一个辅助的空间,不会在完成一个循环后清空,会一直保持,它的内容来自使用h,H,g,G命令得来。

sed读取输入流的一行,在读取下一行之前,需要做如下操作(完成这些操作视为完成一个循环):sed从输入流读取一行,删除换行符,并把内容放到pattern space。然后命令开始对pattern space进行操作。每个命令可以有address关联,如/devops.webres.wang/a\hello,/devops.webres.wang/是搜索包括devops.webres.wang的pattern space,然后再执行a\hello增加hello字符操作,/devops.webres.wang/即为address,a为命令。只有address为真时,即匹配成功时,才执行后面的命令。

除非使用特殊的命令,如”D”,否则pattern space会在两个循环之间被清空。而hold space则会保持不变,hold space的内容可以使用‘h’, ‘H’, ‘x’, ‘g’, ‘G’的命令来操作。

高级应用示例分析

下面的例子来自http://www.gnu.org/software/sed/manual/sed.html
示例一
下面的脚本实现了每行80列宽中间对齐,假如文件中有aabb和ccccdddd两行。

  1. #!/usr/bin/sed -f
  2.     
  3.      # Put 80 spaces in the buffer
  4.      1 {
  5.        x
  6.        s/^$/          /
  7.        s/^.*$/&&&&&&&&/
  8.        x
  9.      }
  10.     
  11.      # del leading and trailing spaces
  12.      y/t/ /
  13.      s/^ *//
  14.      s/ *$//
  15.     
  16.      # add a newline and 80 spaces to end of line
  17.      G
  18.     
  19.      # keep first 81 chars (80 + a newline)
  20.      s/^(.{81}).*$/1/
  21.     
  22.      # 2 matches half of the spaces, which are moved to the beginning
  23.      s/^(.*)n(.*)2/21/

代码分析:

  1. 读取第一行时,pattern space为aabb,hold space为空。
  2. 以下命令分析:
  3. 1 {
  4.    x
  5.    s/^$/          /
  6.    s/^.*$/&&&&&&&&/
  7.    x
  8.    }
  9. 匹配第一行,执行如下命令,
  10. 执行x命令:交换pattern space和hold space的内容,结果是,pattern space内容为空,hold space为aabb。
  11. 执行s/^$/          /命令:pattern space为8个空格,hold space不变。
  12. 执行s/^.*$/&&&&&&&&/命令:现在pattern space的空格为80个,hold space不变。
  13. 执行x命令:交换它们的内容,pattern space内容为aabb,hold space为80个空格。
  14.  
  15. 继续执行如下命令:
  16. y/t/ /:替换tab为一个空格
  17. s/^ *//:删除行尾空格
  18. s/ *$//:删除行首空格
  19.  
  20. 执行G命令:pattern space附加一换行符,并附加hold space内容到pattern space,结果是,pattern space为aabb+n+80个空格,hold space保持不变。
  21.  
  22. s/^(.{81}).*$/1/命令:用s命令从行首至行尾取81个字符,包括了换行符。
  23.  
  24. s/^(.*)n(.*)2/21/命令:用正则把pattern space后面的空格分半,并移至行首,这样就实现了80列宽度中间对齐。
  25.  
  26. 继续下面的行读取时,hold space的内容会一直保持不变。

示例二
下面的例子实现了为数字加1的效果,比如一个文件number.txt,文件内容为:

  1. 6

sed代码:

  1. #!/usr/bin/sed -f
  2.     
  3.      /[^0-9]/ d
  4.     
  5.      # replace all leading 9s by _ (any other character except digits, could
  6.      # be used)
  7.      :d
  8.      s/9(_*)$/_1/
  9.      td
  10.     
  11.      # incr last digit only.  The first line adds a most-significant
  12.      # digit of 1 if we have to add a digit.
  13.      #
  14.      # The tn commands are not necessary, but make the thing
  15.      # faster
  16.     
  17.      s/^(_*)$/11/; tn
  18.      s/8(_*)$/91/; tn
  19.      s/7(_*)$/81/; tn
  20.      s/6(_*)$/71/; tn
  21.      s/5(_*)$/61/; tn
  22.      s/4(_*)$/51/; tn
  23.      s/3(_*)$/41/; tn
  24.      s/2(_*)$/31/; tn
  25.      s/1(_*)$/21/; tn
  26.      s/0(_*)$/11/; tn
  27.     
  28.      :n
  29.      y/_/0/

代码分析:

  1. 读取第一行6,放到pattern space,
  2. 执行/[^0-9]/ d:删除不是纯数字的行,pattern space为6
  3. 执行:d :标记下面的命令为子命令,用于跳转
  4. s/9(_*)$/_1/:替换9为_,此时pattern space 6不变。
  5. td :测试label d的子命令是否更改pattern space,如果更改,则跳回d标记处,否则继续往下执行。
  6.  
  7. s/^(_*)$/11/; tn
  8. s/8(_*)$/91/; tn
  9. s/7(_*)$/81/; tn
  10. 执行了以上命令,pattern space还是6
  11. s/6(_*)$/71/; tn
  12. 6替换成了7,此时pattern space为7
  13.  
  14. s/5(_*)$/61/; tn
  15. s/4(_*)$/51/; tn
  16. s/3(_*)$/41/; tn
  17. s/2(_*)$/31/; tn
  18. s/1(_*)$/21/; tn
  19. s/0(_*)$/11/; tn
  20. :n
  21. y/_/0/
  22. 执行以上几个命令,pattern space还是7,打印出7,继续下一循环。

示例三
此例子实现了每行倒序的效果。

  1. #!/usr/bin/sed -f
  2. /../! b
  3.  
  4. # Reverse a line.  Begin embedding the line between two newlines
  5. s/^.*$/n&n/
  6.  
  7. # Move first character at the end.  The regexp matches until
  8. # there are zero or one characters between the markers
  9. tx
  10. 😡
  11. s/(n.)(.*)(.n)/321/
  12. tx
  13.  
  14. # Remove the newline markers
  15. s/n//g

代码分析(以输入abcdef为例):

  1. 读取abcdef,
  2. pattern space为abcdef
  3. /../! b:如果只有一个字符,直接打印,中止此循环,进入下一循环。
  4.  
  5. s/^.*$/n&n/:用两个换行符包围abcdef,此刻pattern space为nabcdefn。
  6.  
  7. 😡
  8. s/(n.)(.*)(.n)/321/
  9. tx
  10.  
  11. 经过s命令后,1为na,2为bcde,3为fn,pattern space变为fnbcdena,此刻首尾字符换了位置。
  12. 执行tx命令,发现pattern space已经改变,跳转到x子命令,继续替换操作。
  13. 再次执行s命令后,换行符中间的字符又首尾调换了一次,pattern space为fencdnba
  14. 再一次s命令,pattern space为fednncba,
  15. 再一次s命令,pattern space不变,
  16. tx检测pattern space不变,于是往下执行,
  17. s/n//g:全局替换n,于是pattern space为fedcba,打印出fedcba。

示例四
下面的示例实现了以行为单位对文件进行倒序查看,相当于linux下的tac命令。

  1. #!/usr/bin/sed -nf
  2.  
  3. # reverse all lines of input, i.e. first line became last, …
  4.  
  5. # from the second line, the buffer (which contains all previous lines)
  6. # is *appended* to current line, so, the order will be reversed
  7. 1! G
  8.  
  9. # on the last line we’re done — print everything
  10. $ p
  11.  
  12. # store everything on the buffer again
  13. h

代码分析:
以文件内容为:
devops.webres.wang
www.baidu.com
www.qq.com
为例:

  1. 读取第一行:
  2. pattern space为devops.webres.wang
  3.  
  4. 1! G,如果不是第一行,执行G,附加一换行符到pattern space,再附加hold space内容到pattern space。此刻pattern space还是devops.webres.wang
  5.  
  6. $ p 如果到文件尾,则打印。
  7.  
  8. h命令:用pattern space内容替换hold space内容,现在pattern space和hold space都为devops.webres.wang。
  9.  
  10. 读取第二行
  11. pattern space为bb,hold space为devops.webres.wang
  12.  
  13. 1! G: pattern space为www.baidu.comndevops.webres.wang
  14. h命令:pattern space和hold space都为www.baidu.comndevops.webres.wang
  15.  
  16. 读取第三行
  17. pattern space为www.qq.com,hold space为www.baidu.comndevops.webres.wang
  18.  
  19. 1! G:pattern space为www.qq.comnwww.baidu.comndevops.webres.wang
  20. h命令:pattern space和hold space都为www.qq.comnwww.baidu.comndevops.webres.wang
  21.  
  22. $ p:已到文件尾,执行打印paatern space操作,结果为:
  23. www.qq.com
  24. www.baidu.com
  25. devops.webres.wang

gnu关于sed教程还有很多示例涉及到sed的高级功能,时间有限,先分析到这里。有空再继续。下篇日志贴出并分析使用sed解析nginx配置文件中的server {}代码块,实现列出虚拟主机的server_name root等信息,以及指定server_name的虚拟主机删除操作。
最后介绍一个很好用的sed debug工具,它可以显示出所有pattern space和hold space实时状态。http://aurelio.net/projects/sedsed/