实战1. 删除空行(包括由空格组成的空行)
首先要隆重介绍我们的测试文件,因为这是非常特殊的文件:
forrest@ubuntu:~/Public$ cat -v wuhui.txt
1^M
^M
2^M
^M
3^M
^M
4^M
^M
5^M
^M
6^M
^M
^M
我用cat -v选项,显示不可见字符。^M是换行的意思。不过这是不正常的。正常的文件换行符用-v也是看不到的。
这里如下四种空行:
- 单独一个换行符
- N个空格+换行
- N个TAB+换行
- N个(空格&TAB)+换行
对于这个文件,如果使用:
forrest@ubuntu:~/Public$ sed /^$/d wuhui.txt
1
2
3
4
5
6
forrest@ubuntu:~/Public$
是没有效果的。因为由于特殊字符的存在,空行并不是真的空行(^$)。Google了一下,可以使用这个命令来匹配:
forrest@ubuntu:~/Public$ sed /^[[:space:]]*$/d wuhui.txt
1
2
3
4
5
6
forrest@ubuntu:~/Public$
[[:space:]]
表示空格或者tab的集合,这里有点意外的是居然匹配了^M这个不可见的换行符号。另外,注意到[[:space:]]
后面跟着一个*,表示匹配0个或多个。
[[:space:]]
可以用\s表示,如下:
forrest@ubuntu:~/Public$ sed '/^\s*$/d' wuhui.txt
1
2
3
4
5
6
forrest@ubuntu:~/Public$
但是使用转义字符,一定要对命令添加引号:
forrest@ubuntu:~/Public$ sed /^\s*$/d wuhui.txt
1
2
3
4
5
6
forrest@ubuntu:~/Public$
实战2. 使用正值表达式获取信息——使用括号捕获匹配信息。
假设我们要从svnurl中获取保存本地的目录名,例如:http://svn.alibaba-inc.com/repos/ali_sourcing/apps/web/intl-myalibaba/tags/20110621_r_release4==>$basedir/ali_sourcing/apps/web/intl-myalibaba/
,http://svn.alibaba-inc.com/repos/ali_sourcing/apps/web/intl-myalibaba/branches/20110620_61781_5==>$basedir/ali_sourcing/apps/web/intl-myalibaba/
。
两种思路:一种是保留我们需要的部分,替换我们不需要的部分:
按照这种思路,我们将
http://svn.alibaba-inc.com/repos/ali_sourcing/apps/web/intl-myalibaba/tags/20110621_r_release4
==>$basedir/ali_sourcing/apps/web/intl-myalibaba/tags/20110621_r_release4
==>$basedir/ali_sourcing/apps/web/intl-myalibaba/
于是写出这样的sed语句:
echo $svnurl | sed "s#http://svn.alibaba-inc.com/repos/#$basedir#" | sed 's#\(branches\|tags\)/.*##'
但是这种做法有个问题,就是要匹配的文本一直在变化,后面的sed语句是在前面的基础上执行,对于有变量替换的语句,结局很难预料。比如上面的第二个sed替换,将tags或者branches后面的信息去除,如果第一个sed中增加的$basedir含有这两个关键词(tags和branches),那么就会有问题。
使用RE的一个重要的原则就是匹配文本尽量不变化,即使要变化也必须在可以预知的情况下。这就引出了第二种思路:抽取我们需要的部分,利用它来创建(而不是直接修改原匹配文本)我们需要的信息。
按照这种思路:
http://svn.alibaba-inc.com/repos/ali_sourcing/apps/web/intl-myalibaba/tags/20110621_r_release4
==>ali_sourcing/apps/web/intl-myalibaba/
==>$basedir/ali_sourcing/apps/web/intl-myalibaba/
于是写出了这条sed语句:
echo $svnurl | sed "s#http://svn.alibaba-inc.com/repos/\(.*\)\(?:branches\|tags\).*#$basedir\1#"
其中(?:)表示组合但是不匹配。
写成shell函数就是这个样子:
get_path_from_svnurl()
{
local svnurl=$1
local basedir=$2
# sed中有变量,不能用单引号
# 思路1:
# echo $svnurl | sed "s#http://svn.alibaba-inc.com/repos/#$basedir#" | sed 's#\(branches\|tags\)/.*##'
# 思路2:
echo $svnurl | sed "s#http://svn.alibaba-inc.com/repos/\(.*\)\(?:branches\|tags\).*#$basedir\1#"
}