正则基础

正则基础

译者按:原文因为年代久远,文中很多链接早已过期(主要是关于vi、sed等工具的介绍和手册),本译文中已将此类链接删除,如需检查这些链接可以查看上面链接的原文。除此之外基本照原文直译,括号中有“译者按”的部分是译者补充的说明。如有内容方面的问题请直接和Steve Mansor联系,当然,如果你只写中文,也可以和我联系。

目 录

什么是正则表达式


范例

   
简单

   
中级(神奇的咒语)

   
困难(不可思议的象形文字)

不同工具中的正则表达式

什么是正则表达式一个正则表达式,就是用某种模式去匹配一类字符串的一个公式。很多人因为它们看上去比较古怪而且复杂所以不敢去使用——很不幸,这篇文章也不能够改变这一点,不过,经过一点点练习之后我就开始觉得这些复杂的表达式其实写起来还是相当简单的,而且,一旦你弄懂它们,你就能把数小时辛苦而且易错的文本处理工作压缩在几分钟(甚至几秒钟)内完成。正则表达式被各种文本编辑软件、类库(例如Rogue Wave的tools.h++)、脚本工具(像awk/grep/sed)广泛的支持,而且像Microsoft的Visual C++这种交互式IDE也开始支持它了。 
我们将在如下的章节中利用一些例子来解释正则表达式的用法,绝大部分的例子是基于vi中的文本替换命令和grep文件搜索命令来书写的,不过它们都是比较典型的例子,其中的概念可以在sed、awk、perl和其他支持正则表达式的编程语言中使用。你可以看看
不同工具中的正则表达式
这一节,其中有一些在别的工具中使用正则表达式的例子。还有一个关于vi中文本替换命令(s)的
简单说明
附在文后供参考。
正则表达式基础正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义,我们下面会给予解释。 
在最简单的情况下,一个正则表达式看上去就是一个普通的查找串。例如,正则表达式"testing"中没有包含任何元字符,,它可以匹配"testing"和"123testing"等字符串,但是不能匹配"Testing"。
要想真正的用好正则表达式,正确的理解元字符是最重要的事情。下表列出了所有的元字符和对它们的一个简短的描述。 
元字符

描述

.
 
匹配任何单个字符。例如正则表达式r.t匹配这些字符串:ratrutr t,但是不匹配root。 
$ 
匹配行结束符。例如正则表达式weasel$ 能够匹配字符串"He's a weasel"的末尾,但是不能匹配字符串"They are a bunch of weasels."。 
^ 
匹配一行的开始。例如正则表达式^When in能够匹配字符串"When in the course of human events"的开始,但是不能匹配"What and When in the"。
* 
匹配0或多个正好在它之前的那个字符。例如正则表达式.*意味着能够匹配任意数量的任何字符。
\ 
这是引用府,用来将这里列出的这些元字符当作普通的字符来进行匹配。例如正则表达式\$被用来匹配美元符号,而不是行尾,类似的,正则表达式\.用来匹配点字符,而不是任何字符的通配符。
[ ] 
[c1-c2] 
[^c1-c2]
 
匹配括号中的任何一个字符。例如正则表达式r[aou]t匹配ratrotrut,但是不匹配ret。可以在括号中使用连字符-来指定字符的区间,例如正则表达式[0-9]可以匹配任何数字字符;还可以制定多个区间,例如正则表达式[A-Za-z]可以匹配任何大小写字母。另一个重要的用法是“排除”,要想匹配除了指定区间之外的字符——也就是所谓的补集——在左边的括号和第一个字符之间使用^字符,例如正则表达式[^269A-Z] 将匹配除了2、6、9和所有大写字母之外的任何字符。
\ 
匹配词(word)的开始(\)。例如正则表达式\能够匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:这个元字符不是所有的软件都支持的。
\( \) 
将 \( 和 \) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。
| 
将两个匹配条件进行逻辑“或”(Or)运算。例如正则表达式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:这个元字符不是所有的软件都支持的。
+ 
匹配1或多个正好在它之前的那个字符。例如正则表达式9+匹配9、99、999等。注意:这个元字符不是所有的软件都支持的。
? 
匹配0或1个正好在它之前的那个字符。注意:这个元字符不是所有的软件都支持的。
\{i\} 
\{i,j\}
 
匹配指定数目的字符,这些字符是在它之前的表达式定义的。例如正则表达式A[0-9]\{3\} 能够匹配字符"A"后面跟着正好3个数字字符的串,例如A123、A348等,但是不匹配A1234。而正则表达式[0-9]\{4,6\} 匹配连续的任意4个、5个或者6个数字字符。注意:这个元字符不是所有的软件都支持的。

最简单的元字符是点,它能够匹配任何单个字符(注意包括新行符)。假定有个文件test.txt包含以下几行内容:
  • he is a rat
    he is in a rut
    the food is Rotten
    I like root beer
我们可以使用grep命令来测试我们的正则表达式,grep命令使用正则表达式去尝试匹配指定文件的每一行,并将至少有一处匹配表达式的所有行显示出来。命令 
  • grep r.t test.txt
在test.txt文件中的每一行中搜索正则表达式 r.t,并打印输出匹配的行。正则表达式 r.t匹配一个 r接着任何一个字符再接着一个 t。所以它将匹配文件中的 ratrut,而不能匹配 Rotten中的 Rot,因为正则表达式是大小写敏感的。要想同时匹配大写和小写字母,应该使用字符区间元字符(方括号)。正则表达式 [Rr]能够同时匹配 Rr。所以,要想匹配一个大写或者小写的 r接着任何一个字符再接着一个 t就要使用这个表达式: [Rr].t。 
要想匹配行首的字符要使用抑扬字符(^)——又是也被叫做插入符。例如,想找到text.txt中行首"he"打头的行,你可能会先用简单表达式 he,但是这会匹配第三行的 the,所以要使用正则表达式 ^he,它只匹配在行首出现的 h。 
有时候指定“除了×××都匹配”会比较容易达到目的,当抑扬字符(^)出现在方括号中是,它表示“排除”,例如要匹配 he ,但是排除前面是 t or  s的情性(也就是 theshe),可以使用: [^st]he。 
可以使用方括号来指定多个字符区间。例如正则表达式 [A-Za-z]匹配任何字母,包括大写和小写的;正则表达式 [A-Za-z][A-Za-z]* 匹配一个字母后面接着0或者多个字母(大写或者小写)。当然我们也可以用元字符 +做到同样的事情,也就是: [A-Za-z]+ ,和 [A-Za-z][A-Za-z]*完全等价。但是要注意元字符 + 并不是所有支持正则表达式的程序都支持的。关于这一点可以参考后面的
正则表达式语法支持情况

要指定特定数量的匹配,要使用大括号(注意必须使用反斜杠来转义)。想匹配所有 1001000的实例而排除 1010000,可以使用: 10\{2,3\},这个正则表达式匹配数字1后面跟着2或者3个0的模式。在这个元字符的使用中一个有用的变化是忽略第二个数字,例如正则表达式 0\{3,\} 将匹配至少3个连续的0。
简单的例子
这里有一些有代表性的、比较简单的例子。 
vi 命令
作用

:%s/ */ /g

把一个或者多个空格替换为一个空格。
:%s/ *$//
去掉行尾的所有空格。
:%s/^/ /
在每一行头上加入一个空格。
:%s/^[0-9][0-9]* //
去掉行首的所有数字字符。
:%s/b[aeio]g/bug/g
将所有的 bagbegbigbog改为 bug。 
:%s/t\([aou]\)g/h\1t/g
将所有 tagtogtug分别改为 hathothug(注意用group的用法和使用\1引用前面被匹配的字符)。
中级的例子(神奇的咒语)
例1
将所有方法foo( a,b,c)的实例改为foo( b,a,c)。这里a、b和c可以是任何提供给方法foo()的参数。也就是说我们要实现这样的转换: 
之前

之后

foo(10,7,2)
foo(7,10,2)
foo(x+13,y-2,10)
foo(y-2,x+13,10)
foo( bar(8), x+y+z, 5)
foo( x+y+z, bar(8), 5)
下面这条替换命令能够实现这一魔法:
  • :%s/foo(\([^,]*\),\([^,]*\),\([^)]*\))/foo(\2,\1,\3)/g

现在让我们把它打散来加以分析。写出这个表达式的基本思路是找出foo()和它的括号中的三个参数的位置。第一个参数是用这个表达式来识别的:: \([^,]*\),我们可以从里向外来分析它:  
[^,]

除了逗号之外的任何字符
[^,]*
0或者多个非逗号字符
\([^,]*\)
将这些非逗号字符标记为 \1,这样可以在之后的替换模式表达式中引用它
\([^,]*\),
我们必须找到0或者多个非逗号字符后面跟着一个逗号,并且非逗号字符那部分要标记出来以备后用。
现在正是指出一个使用正则表达式常见错误的最佳时机。为什么我们要使用 [^,]*这样的一个表达式,而不是更加简单直接的写法,例如: .*,来匹配第一个参数呢?设想我们使用模式 .*来匹配字符串"10,7,2",它应该匹配"10,"还是"10,7,"?为了解决这个两义性(ambiguity),正则表达式规定一律按照最长的串来,在上面的例子中就是"10,7,",显然这样就找出了两个参数而不是我们期望的一个。所以,我们要使用 [^,]*来强制取出第一个逗号之前的部分。
这个表达式我们已经分析到了: foo(\([^,]*\),这一段可以简单的翻译为“当你找到 foo(就把其后直到第一个逗号之前的部分标记为 \1”。然后我们使用同样的办法标记第二个参数为 \2。对第三个参数的标记方法也是一样,只是我们要搜索所有的字符直到右括号。我们并没有必要去搜索第三个参数,因为我们不需要调整它的位置,但是这样的模式能够保证我们只去替换那些有三个参数的foo()方法调用,在foo()是一个重载(overoading)方法时这种明确的模式往往是比较保险的。然后,在替换部分,我们找到foo()的对应实例,然后利用标记好的部分进行替换,是的第一和第二个参数交换位置。
例2假设有一个CSV(comma separated value)文件,里面有一些我们需要的信息,但是格式却有问题,目前数据的列顺序是:姓名,公司名,州名缩写,邮政编码,现在我们希望讲这些数据重新组织,以便在我们的某个软件中使用,需要的格式为:姓名,州名缩写-邮政编码,公司名。也就是说,我们要调整列顺序,还要合并两个列来构成一个新列。另外,我们的软件不能接受逗号前后面有任何空格(包括空格和制表符)所以我们还必须要去掉逗号前后的所有空格。 
这里有几行我们现在的数据:
  • Bill Jones,     HI-TEK Corporation ,  CA, 95011
    Sharon Lee Smith,  Design Works Incorporated,  CA, 95012
    B. Amos   ,  Hill Street Cafe,  CA, 95013
    Alexander Weatherworth,  The Crafts Store,  CA, 95014
    ...
我们希望把它变成这个样子: 
  • Bill Jones,CA 95011,HI-TEK Corporation
    Sharon Lee Smith,CA 95012,Design Works Incorporated
    B. Amos,CA 95013,Hill Street Cafe
    Alexander Weatherworth,CA 95014,The Crafts Store
    ...
我们将用两个正则表达式来解决这个问题。第一个移动列和合并列,第二个用来去掉空格。 
下面就是第一个替换命令:
  • :%s/\([^,]*\),\([^,]*\),\([^,]*\),\(.*\)/\1,\3 \4,\2/
这里的方法跟例1基本一样,第一个列(姓名)用这个表达式来匹配: \([^,]*\),即第一个逗号之前的所有字符,而姓名内容被用 \1标记下来。公司名和州名缩写字段用同样的方法标记为 \2\3,而最后一个字段用 \(.*\)来匹配("匹配所有字符直到行末")。替换部分则引用上面标记的那些内容来进行构造。 
下面这个替换命令则用来去除空格:
  • :%s/[ \t]*,[ \t]*/,/g
我们还是分解来看: [ \t]匹配空格/制表符, [ \t]* 匹配0或多个空格/制表符, [ \t]*,匹配0或多个空格/制表符后面再加一个逗号,最后, [ \t]*,[ \t]*匹配0或多个空格/制表符接着一个逗号再接着0或多个空格/制表符。在替换部分,我们简单的我们找到的所有东西替换成一个逗号。这里我们使用了结尾的可选的 g参数,这表示在每行中对所有匹配的串执行替换(而不是缺省的只替换第一个匹配串)。 
例3假设有一个多字符的片断重复出现,例如: 
Billy tried really hard 
Sally tried really really hard 
Timmy tried really really really hard 
Johnny tried really really really really hard而你想把"really"、"really really",以及任意数量连续出现的"really"字符串换成一个简单的"very"(simple is good!),那么以下命令: 
:%s/\(really \)\(really \)*/very /就会把上述的文本变成: 
Billy tried very hard 
Sally tried very hard 
Timmy tried very hard 
Johnny tried very hard表达式 \(really \)*匹配0或多个连续的"really "(注意结尾有个空格),而 \(really \)\(really \)* 匹配1个或多个连续的"really "实例。 
困难的例子(不可思议的象形文字) Coming soon

不同工具中的正则表达式OK,你已经准备使用RE(regular expressions,正则表达式),但是你并准备使用vi。所以,在这里我们给出一些在其他工具中使用RE的例子。另外,我还会总结一下你在不同程序之间使用RE可能发现的区别。 
当然,你也可以在Visual C++编辑器中使用RE。选择Edit->Replace,然后选择"Regular expression"选择框,Find What输入框对应上面介绍的vi命令 :%s/pat1/pat2/g中的pat1部分,而Replace输入框对应pat2部分。但是,为了得到vi的执行范围和 g选项,你要使用Replace All或者适当的手工Find Next and Replace(译者按:知道为啥有人骂微软弱智了吧,虽然VC中可以选中一个范围的文本,然后在其中执行替换,但是总之不够vi那么灵活和典雅)。
sed
Sed是 Stream  EDitor的缩写,是Unix下常用的基于文件和管道的编辑工具,可以在手册中得到关于sed的详细信息。 
这里是一些有趣的sed脚本,假定我们正在处理一个叫做price.txt的文件。注意这些编辑并不会改变源文件,sed只是处理源文件的每一行并把结果显示在标准输出中(当然很容易使用重定向来定制): 
sed脚本

描述

sed 's/^$/d' price.txt

删除所有空行
sed 's/^[ \t]*$/d' price.txt
删除所有只包含空格或者制表符的行
sed 's/"//g' price.txt
删除所有引号
awkawk是一种编程语言,可以用来对文本数据进行复杂的分析和处理。可以在手册中得到关于awk的详细信息。这个古怪的名字是它作者们的姓的缩写(Aho,Weinberger和Kernighan)。 
在Aho,Weinberger和Kernighan的书 The AWK Programming Language中有很多很好的awk的例子,请不要让下面这些微不足道的脚本例子限制你对awk强大能力的理解。我们同样假定我们针对price.txt文件进行处理,跟sed一样,awk也只是把结果显示在终端上。  
awk脚本

描述

awk '$0 !~ /^$/' price.txt

删除所有空行
awk 'NF > 0' price.txt
awk中一个更好的删除所有行的办法
awk '$2 ~ /^[JT]/ {print $3}' price.txt
打印所有第二个字段是'J'或者'T'打头的行中的第三个字段
awk '$2 !~ /[Mm]isc/ {print $3 + $4}' price.txt
针对所有第二个字段不包含'Misc'或者'misc'的行,打印第3和第4列的和(假定为数字)
awk '$3 !~ /^[0-9]+\.[0-9]*$/ {print $0}' price.txt
打印所有第三个字段不是数字的行,这里数字是指d.d或者d这样的形式,其中d是0到9的任何数字
awk '$2 ~ /John|Fred/ {print $0}' price.txt
如果第二个字段包含'John'或者'Fred'则打印整行
grepgrep是一个用来在一个或者多个文件或者输入流中使用RE进行查找的程序。它的name编程语言可以用来针对文件和管道进行处理。可以在手册中得到关于grep的完整信息。这个同样古怪的名字来源于vi的一个命令, g/ re /p,意思是 global  regular  expression  print。 
下面的例子中我们假定在文件phone.txt中包含以下的文本,——其格式是姓加一个逗号,然后是名,然后是一个制表符,然后是电话号码:

  • Francis, John           5-3871 
    Wong, Fred              4-4123 
    Jones, Thomas           1-4122 
    Salazar, Richard        5-2522

grep命令

描述

grep '\t5-...1' phone.txt

把所有电话号码以5开头以1结束的行打印出来,注意制表符是用 \t表示的
grep '^S[^ ]* R' phone.txt
打印所有姓以S打头和名以R打头的行
grep '^[JW]' phone.txt
打印所有姓开头是J或者W的行
grep ', ....\t' phone.txt
打印所有姓是4个字符的行,注意制表符是用 \t表示的
grep -v '^[JW]' phone.txt
打印所有不以J或者W开头的行
grep '^[M-Z]' phone.txt
打印所有姓的开头是M到Z之间任一字符的行
grep '^[M-Z].*[12]' phone.txt
打印所有姓的开头是M到Z之间任一字符,并且点号号码结尾是1或者2的行
egrepegrep是grep的一个扩展版本,它在它的正则表达式中支持更多的元字符。下面的例子中我们假定在文件phone.txt中包含以下的文本,——其格式是姓加一个逗号,然后是名,然后是一个制表符,然后是电话号码: 
  • Francis, John           5-3871
    Wong, Fred              4-4123
    Jones, Thomas           1-4122
    Salazar, Richard        5-2522

egrep command

Description

egrep '(John|Fred)' phone.txt

打印所有包含名字 John或者 Fred的行
egrep 'John|22$|^W' phone.txt
打印所有包含 John 或者以22结束或者以 W的行
egrep 'net(work)?s' report.txt
从report.txt中找到所有包含 networks或者 nets的行
正则表达式语法支持情况
命令或环境
.
[ ]
^
$
\( \)
\{ \}
?
+
|
( )

vi










Visual C++










awk










sed










Tcl










ex










grep










egrep

X








fgrep










perl
X
X
X
X
X

X
X
X
X

vi替换命令简介Vi的替换命令: 
  • : range s/ pat1 / pat2 /g
其中 
  • : 这是Vi的命令执行界面。

  • range 是命令执行范围的指定,可以使用百分号(%)表示所有行,使用点(.)表示当前行,使用美元符号($)表示最后一行。你还可以使用行号,例如 10,20表示第10到20行, .,$表示当前行到最后一行, .+2,$-5表示当前行后两行直到全文的倒数第五行,等等。 
    s 表示其后是一个替换命令。
    pat1 这是要查找的一个正则表达式,这篇文章中有一大堆例子。

  • pat2 这是希望把匹配串变成的模式的正则表达式,这篇文章中有一大堆例子。 
    g 可选标志,带这个标志表示替换将针对行中每个匹配的串进行,否则则只替换行中第一个匹配串。
网上有很多vi的在线手册,你可以访问他们以获得更加完整的信息。
4.2. 使用grep的例子
4.2.1. 什么是grep?
grep 以行为单位搜索那些包含给出模板列表的输入文件。当在一行中找到匹配,默认把该行拷贝到标准输出(默认),或者其他你以选项要求的任何种类的输出。 searches the input files for lines containing a match to a given pattern list. When it finds a match in a line, it copies the line to standard output (by default), or whatever other sort of output you have requested with options.
尽管 grep 希望在基于文本进行匹配,除了现有的内存它对于输入行的长度没有限制,而且它可以匹配某行的任意字符。如果输入文件的最后一个字节不是一个 换行,grep 就悄悄增加一个。既然换行也是一个模板列表的分隔符,那么就没有办法在一个文本中匹配一个换行字符。
一些例子:
cathy ~> grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
cathy ~> grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
12:operator:x:11:0:operator:/root:/sbin/nologin
cathy ~> grep -v bash /etc/passwd | grep -v nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
news:x:9:13:news:/var/spool/news:
mailnull:x:47:47::/var/spool/mqueue:/dev/null
xfs:x:43:43:X Font Server:/etc/X11/fs:/bin/false
rpc:x:32:32:Portmapper RPC user:/:/bin/false
nscd:x:28:28:NSCD Daemon:/:/bin/false
named:x:25:25:Named:/var/named:/bin/false
squid:x:23:23::/var/spool/squid:/dev/null
ldap:x:55:55:LDAP User:/var/lib/ldap:/bin/false
apache:x:48:48:Apache:/var/www:/bin/false
cathy ~> grep -c false /etc/passwd
7
cathy ~> grep -i ps ~/.bash* | grep -v history
/home/cathy/.bashrc:PS1="\[\033[1;44m\]$USER is in \w\[\033[0m\] "
第一个例子,用户 cathy 把 /etc/passwd 里面包含 root字符串的行显示出来。
然后她显示了包含着个搜索字符串的行的号码。
用第三个命令她检查了哪个用户没有使用 bash,但是使用 nologin shell的账号不会显示。
然后她统计了把 /bin/false 作为shell的账户的数量。
最后的命令显示了在她的home目录中所有包含以 ~/.bash 开头的行的文件,excluding matches containing history, so as to exclude matches from ~/.bash_history which might contain the same string, in upper or lower cases.
现在让我们来看看用正则表达式,grep还能做些什么。
4.2.2. Grep与正则表达式
[注意]     如果你不是在使用Linux
我们在这些例子中使用支持扩展正则表达式的GNU grep。GNU grep 在Linux系统里是默认的。如果你在专有的系统上工作,那么请使用 -V 选项来检查你在使用哪个版本的grep。GNU grep 也可以从 
http://gnu.org/directory/
下载。
4.2.2.1. 锚定行和字
从先前的例子中,我们只想显示那些使用字符串 “root” 开头的行:
cathy ~> grep ^root /etc/passwd
root:x:0:0:root:/root:/bin/bash
如果我们想看哪个账号什么shell都没有分配,我们搜索行结束符 “:”:
cathy ~> grep :$ /etc/passwd
news:x:9:13:news:/var/spool/news:
要检查 PATH 是否在 ~/.bashrc 中导出,首先选择 “export” 然后搜索以字符串 PATH 开始的行,这样就不会搜索到MANPATH或者其他可能的路径了:
cathy ~> grep export ~/.bashrc | grep '\ 匹配字的结束。
如果你想找到是一个分隔的字的字符串(用空格来包围的),最好使用 -w,就像在这个例子中我们现实root分区的信息那样:
cathy ~> grep -w / /etc/fstab
LABEL=/                /                      ext3    defaults        1 1
如果不使用这个选项,系统表中的所有行都会被显示。
4.2.2.2. 字符族Character classes
方括号表达式 是一个用 “[” and “]” 包含起来的字符列表。它匹配任何在列表中的单个字符;如果列表的第一个字符是 “^”,那么它匹配任何不在列表中的字符。比如,正则表达式,“[0123456789]” 匹配任何单个数字。
在一个方括号表达式中,范围表达式range expression 由2个横线分隔的字符组成。它匹配任何排列在2个字符之间的单个字符,包括,使用场合比较序列和字符集。比如,默认的C场合,“[a-d]” 等于 “[abcd]”。许多场合以字典的顺序来对字符进行分类,在这些场合中 “[a-d]” 通常不等于 “[abcd]”;可能等于 “[aBbCcDd]”。比如,为了得到对于方括号表达式的惯用解释,你可以通过设置 LC_ALL 环境变量的值为 “C” 来使用C场合。
最后,特定的命名的字符族是在括号内事先定义的。参见 grep man 或者 info 页面得到更多关于预定义表达式的信息。
cathy ~> grep [yf] /etc/group
sys:x:3:root,bin,adm
tty:x:5:
mail:x:12:mail,postfix
ftp:x:50:
nobody:x:99:
floppy:x:19:
xfs:x:43:
nfsnobody:x:65534:
postfix:x:89:
cathy ~> ls *[1-9].xml
app1.xml  chap1.xml  chap2.xml  chap3.xml  chap4.xml
在这个例子中,所有包含一个 “y” 或者 “f” 字符的行首先显示,之后是一个 ls 命令使用范围的例子。
4.2.2.3. 统配符
使用 “.” 进行一个单字符匹配。如果你想得到一个以 “c” 开头且以 “h” 结尾的所有5位字符的英语辞典词条(来解决 crosswords 游戏,就是那个纵横填字游戏):
cathy ~> grep '\' /usr/share/dict/words
catch
clash
cloth
coach
couch
cough
crash
crush
如果你想显示包含点字符的行,使用 -F 选项给 grep.
要匹配多个字符,使用星号。这个例子从系统的词典中选择了所有以 “c” 开头且以 “h” 结尾的单词:
cathy ~> grep '\' /usr/share/dict/words
caliph
cash
catch
cheesecloth
cheetah
--output omitted--
如果你想在一个文件或者输出中找到包含星号字符的行,使用 grep -F:
cathy ~> grep * /etc/profile
cathy ~> grep -F '*' /etc/profile
for i in /etc/profile.d/*.sh ; do
4.3.1. 字符范围
除了 grep 和正则表达式之外,shell里有很多无需使用外部程序就可以直接使用的匹配模板。
就和你已经知道的一样,*和?分别匹配任何字符串和任何单个字符,引用这些特殊字符来匹配他们的字面值:
cathy ~> touch "*"
cathy ~> ls "*"
*
你也可以使用方括号来匹配任何enclosed character or range of characters,如果一对字符被-分隔,一个例子But you can also use the square braces to match any enclosed character or range of characters, if pairs of characters are separated by a hyphen. An example:
cathy ~> ls -ld [a-cx-z]*
drwxr-xr-x    2 cathy     cathy        4096 Jul 20  2002 app-defaults/
drwxrwxr-x    4 cathy    cathy          4096 May 25  2002 arabic/
drwxrwxr-x    2 cathy    cathy          4096 Mar  4 18:30 bin/
drwxr-xr-x    7 cathy    cathy          4096 Sep  2  2001 crossover/
drwxrwxr-x    3 cathy    cathy          4096 Mar 22  2002 xml/
列出了 cathy home目录里的所有以“a”,“a”,“b”,“c”,“x”,“y”开头的文件。
If the first character within the braces is “!” or “^”, any character not enclosed will be matched. To match the dash (“-”), include it as the first or last character in the set. The sorting depends on the current locale and of the value of the LC_COLLATE variable, if it is set. Mind that other locales might interpret “[a-cx-z]” as “[aBbCcXxYyZz]” if sorting is done in dictionary order. If you want to be sure to have the traditional interpretation of ranges, force this behavior by setting LC_COLLATE or LC_ALL to “C”.
4.3.2. 字符族
字符族可以用方括号来指定,使用语法 [:CLASS:],CALSS是定义在POSIX标准中的取以下某个值
“alnum”, “alpha”, “ascii”, “blank”, “cntrl”, “digit”, “graph”, “lower”, “print”, “punct”, “space”, “upper”, “word” or “xdigit”.
一些例子:
cathy ~> ls -ld [[:digit:]]*
drwxrwxr-x    2 cathy    cathy        4096 Apr 20 13:45 2/
cathy ~> ls -ld [[:upper:]]*
drwxrwxr--    3 cathy  cathy          4096 Sep 30  2001 Nautilus/
drwxrwxr-x    4 cathy  cathy          4096 Jul 11  2002 OpenOffice.org1.0/
-rw-rw-r--    1 cathy  cathy        997376 Apr 18 15:39 Schedule.sdc
当开启 extglob shell选项(使用 shopt 内建命令), several extended pattern matching operators are recognized. Read more in the Bash info pages, section Basic shell features → Shell Expansions → Filename Expansion → Pattern Matching.
下一文章: 
shell入门基础

» 相关连接: 
Unix系列shell程序编写
快速编辑Shell命令行
正则表达式之道
玩转Linux shell命令提示符
shell入门基础
详解Bash命令行处理
Expect 教程中文版
HTTP代理服务器小常识
Ubuntu完全手册(五)
适用范围
CPU技术术语不完全手册



[url=javascript:scroll(0,0)]顶端[/url]
2 楼   From:本地网络 
引用

推荐

编辑
复制 Posted: 2007-12-24 09:13 

#left_vhost_div {background: #fafafa url(/cnscn/imgs/left_vhost_bg.jpg) no-repeat top; border: 1px solid #ddd;padding-top:0px;width:180px;font-size:12px;margin-bottom:0px;float: left;margin-right:0px;} #left_vhost_div ul{   list-style-position: inside; padding:2px; margin-top:2px;  *margin-left:-9px; margin-bottom:3px;  } .img-li { list-style-image: url(/cnscn/imgs/li_ico.gif); font-weight:bold; line-height: 14px; margin-top:2px} .none-li {list-style: none; margin-left:16px; *margin-left:8px; line-height: 16px;} .none-li p {line-height: 14px; margin-bottom:3px; } .none-li p span{margin-left:-5px;*margin-left:18px; }
ASP/.NET/PHP虚拟主机 

  • 基础信息 
    南北 双线
    1000M超大网站空间
    2G MySQL5.0+/SQLServer
    FreeBSD/Nginx/PHP/MySQL
    Win2003/IIS/ASP/.NET
    20G/月超大流量
    cpu占用/并发连接数不限
    价格: 200元
    域名绑定 
    支持多个域名绑定 
    支持10个子站点 
    空间管理 
    FTP / 在线文件管理 
    企业邮局 
    10个企业邮局(每个1G空间) 
    硬件设施 
    多家骨干机房任选 
        北京、上海、广东 
        成都、河北、郑州 
    2-8路酷睿或至强服务器 
    机房带宽 >20G骨干网接入 
    UPS不间断电源 
    本机/外部备份 2次/周 
    多媒体支持 
    音频/视频流媒体支持 
    域名价格 
    .com/.net/.org 50元 
    .cn/.com.cn/.net.cn 15元 
    联系方式 
    网站:
    http://www.dns086.com

    ( 手机: 18918927310 )
    姚先生:
    [url=tencent://message/?uin=214363570&Site=低价域名空间服务商&Menu=yes]

    214363570[/url]
    何先生:
    [url=tencent://message/?uin=34557049&Site=低价域名空间服务商&Menu=yes]

    34557049[/url]
    何先生:
    [url=tencent://message/?uin=330321364&Site=低价域名空间服务商&Menu=yes]

    330321364[/url]
    杨先生:
    [url=tencent://message/?uin=214451305&Site=低价域名空间服务商&Menu=yes]

    214451305[/url]
    刘先生:
    [url=tencent://message/?uin=21113641&Site=低价域名空间服务商&Menu=yes]

    21113641[/url]
    吴先生:
    [url=tencent://message/?uin=34238063&Site=低价域名空间服务商&Menu=yes]

    34238063[/url]
    黎先生:
    [url=tencent://message/?uin=16010133&Site=低价域名空间服务商&Menu=yes]

    16010133[/url]


2007 年 5 月 28 日
几乎所有重要问题都需要从无用数据中过滤出有用数据。了解大量的 UNIX® 命令行实用工具如何使用 正则表达式 来去芜取精。 
非常奇怪,直到今天我仍然能重复周六早上的经典歌曲“Conjunction Junction”。这是好事(看了太多电视)还是坏事(也许是我现在职业的先兆)仍然有待讨论。不管怎样,这首小调在欢快的节奏下传递了基本的信息。
我还没有为学习 UNIX 构想出与“Conjunction Junction”相似的作品,但是我会在未来的几个月里尝试亲手编写这样的歌曲。与此同时,趁着快乐回忆所带来的好心情,我们继续以 Schoolhouse 摇滚的传统学习方式攻克命令行。
现在开始上课。吐出嘴里的口香糖,回到您的座位上,然后拿出一根二号铅笔。还有您,Spicoli。
模仿秀
您可以将 UNIX 命令行看作是一句话:

  • 可执行命令,如 cat 或 ls,是动词——操作。 
  • 命令的输出是名词——要查阅或使用的数据。 
  • Shell 操作符,如 |(管道)或 >(重定向标准输出),是连词——用于连接句子。

例如,命令行:ls -A | wc -l 用于计算当前目录下的条目数(忽略特殊条目 . 和 ..),它包含两个句子。第一个句子 ls -A 是动词结构,列举当前目录下的内容,第二个句子 wc -l 是另一个动词结构,用于计算行数。第一个句子输出的结果作为第二个句子的输入,并由连接词(管道)连接这两个句子。
在本系列文章以及其他文章中展示的许多您可能已经学习过的命令行句式都具有这种句子结构。
但是,如果缺少了文法上的修饰语,命令行将显得不专业。当然,基本句子也能完成工作,但是这样显得不 优美。(在此对高中英语演唱二人组 Rad 女士和 Perlstein 女士表示歉意。)解决更有趣的问题需要用到 形容词
几乎所有重要问题都需要从无用数据中过滤出有用数据。虽然属性的数量和种类会有所不同,但是每种方案都通过某种方式(形式或格式),隐式或显式地描述了它要查找并处理的信息,从而生成另外一种形式的其他信息。
在命令行中, 正则表达式 的作用相当于形容词——一种描述或限定词。在应用到输出时,正则表达式可辨别相关数据和无关数据。
标点概述
让我们看一个示例问题。
grep 实用工具逐行过滤输入并寻找匹配。grep 的最简单应用是打印那些包含与某个模式匹配的文本的行。grep 可以查找具有固定顺序的字符组合,甚至可以通过使用 -i 选项来忽略大小写。
因此,假定文件 heroes.txt 包含以下行:
Catwoman
Batman
The Tick
Spider Man
Black Cat
Batgirl
Danger Girl
Wonder Woman
Luke Cage
The Punisher
Ant Man
Dead Girl
Aquaman
SCUD
Spider Woman
Blackbolt
Martian Manhunter
命令行:
grep -i man heroes.txt
将生成:
Catwoman
Batman
Spider Man
Wonder Woman
Ant Man
Aquaman
Martian Manhunter
其中 grep 扫描 heroes.txt 文件中的每一行并查找字母  m,后面紧跟  a,然后紧跟  n。除了必须保证相邻,这些字母可以出现在行的任何位置,甚至可以位于较大的单词中间。在不考虑大小写的情况下(-i 选项),Catwoman、Batman、Spider Man、Wonder Woman、Ant Man、Aquaman 和 Martian Manhunter 都包含字符串 man。
grep 实用工具包含其他可优化搜索的内置选项。例如,-w 选项限制于匹配整个单词,因此 grep -i -w man 将 排除 Catwoman 和 Batman(举例来说)。
该工具还有一个优秀的功能,可以排除而不是包括所有匹配的搜索结果。使用 -v 选项来 排除 匹配的行。例如:
grep -v -i 'spider' heroes.txt
将打印除了包含字符串 spider 之外的所有行。
Catwoman
Batman
The Tick
Black Cat
Batgirl
Danger Girl
Wonder Woman
Luke Cage
The Punisher
Ant Man
Dead Girl
Aquaman
SCUD
Blackbolt
Martian Manhunter
但是,对于以下这些情况,您该如何处理?只希望得到那些 开头为“Bat”的单词;或者以“bat”、“Bat”、“cat”或“Cat”开头的单词?或者希望知道有多少漫画复仇者的名字以“man” 结束。在这些实例中,类似于上述三个示例的简单字符串搜索将无法满足要求,因为这些搜索不区分位置。
位置、位置、位置和备选项
正则表达式 可以 过滤特定的位置,例如行的开始或结束,以及单词的开始和结束。正则表达式(通常简写为  regex)还可以描述:备选项(您可将其称为“this”或“that”);固定长度、可变长度或不定长度的重复;范围(例如,“a-m 之间的任意字母”);还有字符的类别或种类(“可打印字符”或“标点符号”),以及其他技术。
表 1
显示了一些常用的正则表达式操作符。您可以连接
表 1
中显示的元素(以及其他操作符)并加以组合使用,从而构建(非常)复杂的正则表达式。
表 1. 常用的正则表达式操作符
操作符
用途
.(句号)
匹配任意单个字符。
^(脱字号)
匹配出现在行首或字符串开始位置的空字符串。
$(美元符号)
匹配出现在行末的空字符串。

匹配大写字母  A

匹配小写字母  a
\d 
匹配任意一位数字。
\D 
匹配任意单个非数字字符。
\w 
匹配任意单个字母数字字符,同义词是 [:alnum:]。
[A-E] 
匹配任意大写的  A、B、C、D 或  E
[^A-E] 
匹配 除 A、B、C、D 和  E 之外的任意字符。
X? 
匹配出现零次或一次的大写字母  X
X* 
匹配零个或任意个大写  X
X+ 
匹配一个或多个字母  X
X{ n
精确匹配  n 个字母  X
X{ n,m
匹配最少  n 个并且不超过  m 个字母  X。如果省略  m,表达式将尝试匹配最少  n 个 X
(abc|def)+ 
匹配一连串的(最少一个) abc 或 def;abc 和 def 将匹配。
以下是一些使用 grep 作为搜索工具的正则表达式示例。许多其他 UNIX 工具,包括交互式编辑器 vi 和 Emacs、流编辑器 sed 和 awk,以及所有现代编程语言都支持正则表达式。在您学会正则表达式的语法(也许相当晦涩)之后,就可以将您的专业知识灵活运用到不同的工具、编程语言和操作系统。
查找以“Bat”开头的名称
要查找以“Bat”开头的名称,请使用:
grep -E '^Bat'
可以使用 -E 选项来指定正则表达式。^(脱字号)字符匹配行首或字符串的开头,这是一个出现在每行或每个字符串开头字符之前的假想字符。字母 B、a 和 t 只具有字面含义并且仅匹配那些特定的字符。因此,命令 grep -E '^Bat' 将生成:
Batman
Batgirl
由于许多 regex 操作符也为 Shell 所使用(其中一些具有不同的用途,另外一些则有类似的用途),因此一个好的习惯是使用单引号将命令行中的每个 regex 括起来,以保护 regex 操作符免遭 Shell 的误解。例如,*(星号)和 $(美元符号)都是 regex 操作符,并且对于您的 Shell 具有特殊的含义。
查找以“man”结尾的名称
要查找以“man”结尾的名称,可以使用 regex man$ 来匹配序列 m、a 和 n,并且后面紧接与 regex 操作符 $ 匹配的行(字符串)。
查找空行
基于 ^ 和 $ 的作用,您可以使用 regex ^$ 来查找空行(相当于在开始之后立即结束的行)。
备选项或集合操作符
要查找以“bat”、“Bat”、“cat”或“Cat”开头的单词,可以使用以下两个技巧。首先是 备选项,如果备选项中的 任意 模式匹配,都会产生匹配的结果。例如,命令:
grep -E '^(bat|Bat|cat|Cat)' heroes.txt
可实现这一技巧。regex 操作符 |(竖线)表示备选项,因此 this|that 匹配字符串 this 或字符串 that。因此,^(bat|Bat|cat|Cat) 表示“行首紧跟 bat、Bat、cat 或 Cat之一。”当然,可以使用 grep -i 来简化该 regex,这样可以忽略大小写,从而将命令简化为:
grep -i -E '^(bat|cat)' heroes.txt
匹配“bat”、“Bat”、“cat”或“Cat”的另一个方法是使用 [ ](方括号) 集合 操作符。如果将一组字符放在一个集合中,则可以匹配那些字符中的任意一个。(您可以将 集合 看作是字符备选项的简写法。)
例如,命令行:
grep -E '^[bcBC]at' heroes.txt
与以下命令生成的结果相同:
grep -E '^(bat|Bat|cat|Cat)' heroes.txt
您可以再次使用 -i 将 regex 简化为 ^[bc]at。
而且,还可以使用 -(连字符)操作符在集合中指定包含的字符范围。例如,用户名通常以字母开头。假定要在提交给您的服务器的 Web 表格中验证这样的用户名,可以使用类似于 ^[A-Za-z] 的 regex。此 regex 表示“字符串的开头后紧跟任意大写字母 ( A-Z) 或任意小写字母 ( a-z)。”顺便说明一下,[A-z] 与 [A-Za-z] 作用相同。
还可以在集合中混合使用范围和单个字符。regex [A-MXYZ] 将匹配任意大写的  A-M、X、Y 和  Z。 
并且,如果希望反转集合(即排除集合中的任意字符),可以使用特殊集合 [^ ] 并包含要排除的范围或字符。以下是反转集合的示例。要查找所有名称中包含  at 的超级英雄,并排除 Dark Knight 和 Batman,请键入:
grep -i -E '[^b]at' heroes.txt 
此命令生成:
Catwoman
Black Cat
由于某些集合需要经常使用,所以设计出简化符号以代替大量字符。例如,集合 [A-z0-9_] 十分常用,因此可以简写为 \w。与此类似,操作符 \W 是集合 [^A-z0-9_] 的简写。还可以使用符号 [:alnum:] 代替 \w,使用 [^[:alnum:]] 代替 \W。
顺便说明一下,\w(以及同义词 [:alnum:])是特定于区域的,而 [A-z0-9_] 即表示字母  A-z、数字  0-9 和下划线。如果要开发国际化应用程序,请使用区域特定的格式以使代码可以在许多区域之间移植。
跟我一起重复:重复,重复,重复
到目前为止,已经介绍了字面值、位置和两种备选项操作符。仅使用这些内容,就可以匹配大多数具有 可预测 长度的模式。现在回到用户名,通过以下 regex 命令可以确保每个用户名以字母开头并紧跟恰好七个字母或数字:
[a-z][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]
但是这样有点笨拙。而且,它只匹配恰好八个字符的用户名。它不会匹配三到八个字符之间的名称,这通常也是有效的用户名。
正则表达式还可以包括 重复修饰符。重复修饰符可以指定数量,如没有、一个、多个、一个或多个,零或一个、五到十个,以及恰好三个。重复修饰符必须与其他模式组合,修饰符本身没有含义。
例如,regex:
^[A-z][A-z0-9]{2,7}$
可以实现前面描述的用户名过滤功能。 用户名 是以字母开头,后面紧跟至少两个,但不超过七个字母或数字的字符串,并且紧跟字符串结尾。
此处的位置定位点非常重要。如果没有两个位置操作符,则会错误地接受任意长度的用户名。为什么呢?请考虑 regex:
^[A-z][A-z0-9]{2,7}
此命令辨别:字符串是否以字母开头并紧跟二到七个字母?但是它未提到终止条件。因此,字符串 samuelclemens 满足条件,但是它的长度显然超出了有效用户名的范围。与此类似,省略开始定位点 ^,或同时省略两个定位点将分别匹配以类似 munster1313 结束或包含该字符串的字符串。如果必须匹配特定的长度,请记得在要求的模式的开头和结尾分别加上分隔符。
以下是其他一些示例:

  • 可以使用 {2,} 查找两次或多次重复。regex ^G[o]{2,}gle 匹配 Google、Gooogle、Goooogle 等等。 
  • 重复修饰符 ?、+ 和 * 分别查找零次或一次、一次或多次,以及零次或多次重复。(例如,您可以将 ? 看作是 {0,1} 的简写法。) 
    regex boys? 匹配 boy 或 boys;regex Goo?gle 匹配 Gogle 或 Google。
    regex Goo+gle 匹配 Google、Gooogle、Goooogle 等等。
    construct Goo*gle 匹配 Gogle、Google、Gooogle 等等。
  • 可以将重复修饰符应用到单个字符(如上所示),还可以应用到更复杂的组合。使用 ( 和 ) 圆括号(就像数学中的用法)将修饰符应用到子表达式。下面是一个示例:给定文本文件 test.txt: 
    The rain in Spain falls mainly 
    on the the plain.
    It was the best of of times;
    it was the worst of times.
    命令 grep -i -E '(\b(of|the)\W+){2,}' test.txt 将生成:
    on the the plain.
    It was the best of of times;
  • regex 操作符 \b 匹配单词边界 或 (\W\w|\w\W)。该 regex 表示“一连串完整单词‘the’或‘of’后面紧跟非文字字符。”您可能会提出疑问,为什么 \W+ 是必需的:\b 是位于单词开头或结尾的空字符串。在单词之间必须包括这一(或这些)字符,否则该 regex 将无法找到匹配。

捕获需要注意的内容
查找文本是常见的问题,但是更常见的问题则是希望在找到文本之后将其提取出来。换句话说,您希望去粗取精。
正则表达式通过 捕获 来提取信息。如果希望将需要的文本与其他内容分开,请使用圆括号将模式括起来。实际上,您已经使用圆括号收集术语;在默认情况下,圆括号自动进行捕获。
要查看捕获,请切换到 Perl。(grep 实用工具不支持捕获,因为其目标是打印包含模式的行。) 
以下命令:
perl -n -e '/^The\s+(.*)$/ && print "$1\n"' heroes.txt
将打印:
Tick
Punisher
使用命令 perl -e 可以直接从命令行运行 Perl 程序。perl -n 命令针对输入文件的每一行运行一次程序。命令的 regex 部分,即位于斜杠之间的文本(/)表示“匹配字符串的开头,然后字母‘T’、‘h’、‘e’后紧跟一个或多个空格字符 \s+,然后捕获直到字符串结尾的所有字符。
Perl 捕获内容被放在以 $1 开头的特殊 Perl 变量中。Perl 程序的其余部分打印捕获的内容。
每个嵌套的括号对,从左开始算起,每个左圆括号加一,放在下一个特殊的数字变量中。例如:
perl -n -e '/^(\w)+-(\w+)$/ && print "$1 $2"' 
将生成:
Spider Man
Ant Man
Spider Woman
捕获感兴趣的文本仅仅是隔靴搔痒。如果能够准确确定材料,就可以使用其他材料改变其外观。类似于 vi 和 Emacs 的编辑器将模式匹配与替换组合,从而将查找和替换文本组合成一步操作。还可以使用模式、替换和 sed 从命令行更改文本。
丰富的主题
正则表达式非常强大;可供使用的操作符的数量庞大,种类繁多。它包含如此丰富的信息和实践知识,我们在这里所能列举的实属凤毛麟角。
幸运的是,有以下三种优秀的正则表达式理论来源可供使用:

  • 如果在您的系统上有 Perl,可以参阅 Perl Regular Expression man 页面(键入 perldoc perlre)。它会提供 regex 的精彩介绍,并包含许多有用的示例。许多编程语言都已采用 Perl 兼容的正则表达式 (PCRE),因此您在此 man 页面读到的内容已被直接转换到 PHP、Python、Java™ 和 Ruby 编程语言,以及许多其他最新工具。 
  • Jeffrey Friedl 编著的《正则表达式》(第三版)被认为是 regex 用法方面的圣经。该书细致、准确、清晰、务实地说明了匹配的工作方式、所有的 regex 操作符、多数优先性(限制 + 和 * 匹配字符的数量),以及更多内容。此外,Friedl 的书还包括一些令人惊叹的正则表达式,可以准确地匹配完全限定的电子邮件地址和其他 Request for Comments (RFC) 特定的字符串。 
  • Nathan Good 编著的 Regular Expression Recipes 一书提供了针对许多常见数据处理和过滤问题的有用的解决方案。如果需要提取邮政编码、电话号码或引用的字符串,请尝试 Nathan 的解决方案。

在命令行中,可以采用许多方法使用正则表达式。几乎每个处理文本的命令都支持某种形式的正则表达式。大多数 Shell 命令语法还或多或少地扩展正则表达式以匹配文件名(尽管操作符的功能可能有所不同)。
例如,键入 ls [a-c] 以查找名为  a、b 或  c 的文件。键入 ls [a-c]* 以查找以  a、b 或  c 开头的所有文件名。此处的 * 在 Shell 中不像 grep 的解释器那样修饰 [a-c],* 被解释为 .*。? 操作符在 Shell 中也可以工作,但是被解释为 .,即匹配任意单个字符。
查看您最喜欢的实用工具或 Shell 的文档以确定哪些 regex 操作符受支持,以及操作符可能具有的独特性。
下课了!
这堂课比往常的时间要长。但是您现在已了解了正则表达式的基本知识。出去放松一下。
在您享受空闲的时候,我将开始编写很快会流行起来的经典歌词“描述 99 个命令的 99 行代码”。
5.3.1. 从文件读取sed命令
多个 sed 命令可以一起放到一个文件中,用 -f 选项来执行。当建立了一个这样的文件,请确保:
    *
      每行的末尾没有多余的空格。
    *
      不能使用引用。
    *
      当进入文本来添加和替换的时候,除了最后行已为的所有行都要以反斜扛结尾。
5.3.2. 写输出文件
当使用重定向符号 >的时候,写输出就完成了。这是一个例子脚本,用来从纯文本文件建立非常简单的HTML文件。
sandy ~> cat script.sed
1i\
\
sed generated html\
\
$a\
\
\
sandy ~> cat txt2html.sh
#!/bin/bash
# This is a simple script that you can use for converting text into HTML.
# First we take out all newline characters, so that the appending only happens
# once, then we replace the newlines.
echo "converting $1..."
SCRIPT="/home/sandy/scripts/script.sed"
NAME="$1"
TEMPFILE="/var/tmp/sed.$PID.tmp"
sed "s/\n/^M/" $1 | sed -f $SCRIPT | sed "s/^M/\n/" > $TEMPFILE
mv $TEMPFILE $NAME
echo "done."
sandy ~>
$1 把第一个参数送到命令中,这个例子中它是要转换的文件的名字:
sandy ~> cat test
line1
line2
line3
更多的位置参数请参见 第 7 章 条件语句。
sandy ~> txt2html.sh test
converting test...
done.
sandy ~> cat test
sed generated html
line1
line2
line3
sandy ~>
这并不是真的是这么完成的;这个例子仅仅证明了 sed 的实际能力。参见 第 6.3 节 “Gawk变量” 得到一个对这个问题来说更好的解决方法,使用 awk BEGIN 和 END 结构。
[注意]     便捷的sed
高级编辑器,支持语法的高亮来识别 sed 语法。如果你忘记反斜杠之类的它将提供很大的帮助。

本文来自ChinaUnix博客,如果查看原文请点: http://blog.chinaunix.net/u2/71769/showart_2051700.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值