Chinaunix首页 | 论坛 | 博客
  • 博客访问: 25882
  • 博文数量: 9
  • 博客积分: 198
  • 博客等级: 入伍新兵
  • 技术积分: 100
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-10 12:34
文章分类
文章存档

2011年(5)

2010年(4)

最近访客

分类:

2010-12-13 10:53:04

    以前在shell终端执行命令的时候老是以为在grep或sed 中用的正则表达式是可以通用的, 但每次发现自已以为能用的表达式在shell中却没有得到自已想要的结果, 每次那样的时候自已都闷半天,觉的没有道理. 后来才发现. 在bash中根本就没有正则表达式这一说. 所以在shell中用的那些* + . 啊之类的都是通配符. 而在shell中用grep 或sed指命中用了那些符号, 是grep或sed(而不是bash)会把这些符号当个正则表达式来解悉, 所以自已在grep或sed 理解的正则表达式用在bash中却发现表达的意思不是自已所想的.现在来对它们一个总结吧.
    通配符(globbing)不是标准的表达式.它有: *, ?, [], ^, $等.那些字符所表达的意思跟正则表达式所表达的意思是不一样的.如,通配符中的* 将不会匹配以点开头的文件.如.bashrc

Overview

wildcard是由shell处理的, 它只会出现在 commandargument 里——既不用在 command_name里, 也不用在 options 上。当在argument中碰到Wildcard时,shell会将其当作路径或文件名去在磁盘上搜寻可能的匹配:若符合要求的匹配存在,则进行代换(路径扩展);否则就将该wildcard作为一个普通字符传递给command,交由command自行处理。总而言之,wildcard 实际上就是一种shell实现的路径扩展功能。在 wildcard 被处理后, shell会先完成该命令的重组,然后再继续处理重组后的命令,直至执行该命令。

       例如,若当前目录下有Cha1Cha2Des三个文件,而我想用grepDes中搜索包含字符串Cha的行,于是写出命令如下:

grep Cha* Des             

当该命令交由shell处理时,首先会将Cha*中的*当作是一个wildcard,于是就会在当前目录中搜索可能的匹配。*作为wildcard而言匹配的是0个或多个的任意字符,于是文件Cha1Cha2符合匹配要求,shell自行完成了该命令的重组,重组后的命令为:

grep Cha1 Cha2 Des     

而这才是最终执行的命令的文本形式。所以命令实际上的动作是试图在文件Cha2Des中寻找包含Cha1字符串的行。这和期望grep所作的动作是大相径庭的。

       可是,如果当前目录下没有可以匹配Cha*的文件或是文件夹(路径),那么shell会因为找不到可能的匹配而放弃*号的代换,将其传递给command处理,重组后的命令如下:

grep Cha* Des             

这也是该情况下最终执行的命令的文本形式。在这种情况下命令的动作和预期的动作却也不是一致的。因为当*号交给grep处理时,*号将不再是表示0个或多个任意的字符了——这是它作为wildcard,在shell中处理时的含义——在grep的处理中,*号是被当作正则表达式中的符号,表示的是其前面的字符出现0次或多次。

若是在第一种情况下,如何才能使重组后的命令为命令,而非命令呢?在shell的命令中,所有的文字可以分为meta literalliteral就是普通的纯文字,对于shell来说没有什么特别的意义;meta则是shell中具有特定功能的特殊保留字符,如< > |等。不严格区分的话,wildcard也可以归入这一类。也就是说,meta就是会在shell中被处理的从而在最终用于执行的命令中丧失了其自身文本形式的特殊字符(从这个角度来说,将wildcard归入meta是有些不妥的,因为wildcard的有可能被替换掉也有可能不被替换)。若是希望能够将shell中的meta以其文本形式进入command的最终执行形态中——像前面我们所希望的一样,就必须告诉shell不要对meta进行处理,command需要使用它们的文本形式。这个工作则是由shell quoting(转义)来完成的。这种处理正是使用regular expression(正则表达式)所必需要用到的:因为regular expression(正则表达式)中有许多特殊字符(可以看作是RE中的meta)和shell中的metawildcard是相同的,所以为了让那些regular expression中的特殊字符能够通过shell传入regular expression就必须对其进行转义。同样,在那些定义了自有的meta的命令中,若是自有的metashell中的metawildcard重复,也要用到shell quoting,如tr

Wildcard(通配符)

*     匹配 0 或多个字符

?      匹配任意单一字符

[list]              匹配 list 中的任意单一字符

[!list]      匹配不在 list 中的任意单一字符

{string1,string2,...}              匹配 sring1 string2 (或更多)其一字符串

例:

a*b  ab之间可以有任意长度的任意字符, 也可以一个也没有, aabcb, axyzb, a012b, ab

a?b  ab之间必须也只能有一个字符, 可以是任意字符, aab, abb, acb, a0b

a[xyz]b   ab之间必须也只能有一个字符, 但只能是 x y z, : axb, ayb, azb

a[!0-9]b  ab之间必须也只能有一个字符, 但不能是阿拉伯数字, axb, aab, a-b

a{abc,xyz,123}b    ab之间只能是abcxyz123这三个字符串之一。

shell中的meta(元素)

下面是一些常用的:

IFS  三者之一组成(我们常用 space )

CR   产生。

=     设定变量。

$     作变量或运算替换(请不要与 shell prompt 搞混了)

>     重导向 stdout

<     重导向 stdin

|      命令管线。

&    重导向 file descriptor ,或将命令置于背境执行。

( )    将其内的命令置于 nested subshell 执行,或用于运算或命令替换。

{ }   将其内的命令置于 non-named function 中执行,或用在变量替换的界定范围。

;      在前一个命令结束时,而忽略其返回值,继续执行下一个命令。

&&  在前一个命令结束时,若返回值为 true,继续执行下一个命令。

||      在前一个命令结束时,若返回值为 false,继续执行下一个命令。

!      执行 history 列表中的命令。

Regular Expression(正则表达式)

锚点(anchor)

用以标识 RE 于句子中的位置所在. 常见有:

^     表示句首. ^abc 表示以 abc 开首的句子.

$     表示句尾. abc$ 表示以 abc 结尾的句子.

\<    表示词首. \表示以 abc 开首的词.

\>    表示词尾. abc\> 表示以 abc 结尾的词.

修饰字符(modifier)

独立表示时本身不具意义, 专门用以修改前一个字元集的出现次数. 常见有:

*     表示前一个字元集的出现次数为0或多次。如ab*c表示ac之间可有0或多个b存在。

?      表示前一个字元集的出现次数为01次。如ab?c表示ac之间可有01b存在。

+     表示前一个字元集的出现次数为1或多次。如ab+c表示ac之间可有1或多个b存在。

{n}  表示前一个字元集的出现次数必须为n. ab{3,}c表示 ac之间必须有3b存在。

{n,} 表示前一个字元集的出现次数至少为n. ab{3,}c表示ac之间至少有3b存在。

{n,m}     表示前一个字元集的出现次数为nm. ab{3,5}c表示ac之间有35b存在。




阅读(1804) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~