shell通配符与文本正则表达式学习笔记

shell通配符 与 文本正则表达式:

wildcard是由shell处理的, 它只会出现在 command的argument 里——既不用在 command_name里,也不用在 options 上。当在argument中碰到Wildcard时,shell会将其当作路径或文件名去在磁盘上搜寻可能的匹配:若符合要求的匹配存在,则进行代换(路径扩展);否则就将该wildcard作为一个普通字符传递给command,交由command自行处理。总而言之,wildcard 实际上就是一种shell实现的路径扩展功能。在 wildcard 被处理后, shell会先完成该命令的重组,然后再继续处理重组后的命令,直至执行该命令。
例如,若当前目录下有Cha1、Cha2和Des三个文件,而我想用grep在Des中搜索包含字符串Cha的行,于是写出命令如下:
grep Cha* Des              ①
当该命令交由shell处理时,首先会将Cha*中的*当作是一个wildcard,于是就会在当前目录中搜索可能的匹配。*作为wildcard而言匹配的是0个或多个的任意字符,于是文件Cha1和Cha2符合匹配要求,shell自行完成了该命令的重组,重组后的命令为:
grep Cha1 Cha2 Des      ②
而这才是最终执行的命令的文本形式。所以命令①实际上的动作是试图在文件Cha2和Des中寻找包含Cha1字符串的行。这和期望grep所作的动作是大相径庭的。可是,如果当前目录下没有可以匹配Cha*的文件或是文件夹(路径),那么shell会因为找不到可能的匹配而放弃*号的代换,将其传递给command处理,重组后的命令如下:
grep Cha* Des              ③
这也是该情况下最终执行的命令的文本形式。在这种情况下命令①的动作和预期的动作却也不是一致的。因为当*号交给grep处理时,*号将不再是表示0个或多个任意的字符了——这是它作为wildcard,在shell中处理时的含义——在grep的处理中,*号是被当作正则表达式中的符号,表示的是其前面的字符出现0次或多次。
若是在第一种情况下,如何才能使重组后的命令为命令③,而非命令②呢?在shell的命令中,所有的文字可以分为meta 与 literal:literal就是普通的纯文字,对于shell来说没有什么特别的意义;meta则是shell中具有特定功能的特殊保留字符,如< > |等。不严格区分的话,wildcard也可以归入这一类。也就是说,meta就是会在shell中被处理的从而在最终用于执行的命令中丧失了其自身文本形式的特殊字符(从这个角度来说,将wildcard归入meta是有些不妥的,因为wildcard的有可能被替换掉也有可能不被替换)。若是希望能够将shell中的meta以其文本形式进入command的最终执行形态中——像前面我们所希望的一样,就必须告诉shell不要对meta进行处理,command需要使用它们的文本形式。这个工作则是由shell quoting(转义)来完成的。这种处理正是使用regular expression(正则表达式)所必需要用到的:因为regular expression(正则表达式)中有许多特殊字符(可以看作是RE中的meta)和shell中的meta及wildcard是相同的,所以为了让那些regular expression中的特殊字符能够通过shell传入regular expression就必须对其进行转义。同样,在那些定义了自有的meta的命令中,若是自有的meta与shell中的meta或wildcard重复,也要用到shell quoting,如tr。

 

Wildcard

*     匹配 0 或多个字符
?      匹配任意单一字符
[list]              匹配 list 中的任意单一字符
[!list]      匹配不在 list 中的任意单一字符
{string1,string2,...}              匹配 sring1 或 string2 (或更多)其一字符串
例:
a*b  a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如aabcb, axyzb, a012b, ab。
a?b  a与b之间必须也只能有一个字符, 可以是任意字符, 如aab, abb, acb, a0b。
a[xyz]b   a与b之间必须也只能有一个字符, 但只能是 x 或 y 或 z, 如: axb, ayb, azb。
a[!0-9]b  a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如axb, aab, a-b。
a{abc,xyz,123}b    a与b之间只能是abc或xyz或123这三个字符串之一。
 
shell中的meta
下面是一些常用的:
IFS  由 <space> 或 <tab> 或 <enter> 三者之一组成(我们常用 space )。
CR   由 <enter> 产生。
=     设定变量。
$     作变量或运算替换(请不要与 shell prompt 搞混了)。
>     重导向 stdout。
<     重导向 stdin。
|      命令管线。
&    重导向 file descriptor ,或将命令置于背境执行。
( )    将其内的命令置于 nested subshell 执行,或用于运算或命令替换。
{ }   将其内的命令置于 non-named function 中执行,或用在变量替换的界定范围。
;      在前一个命令结束时,而忽略其返回值,继续执行下一个命令。
&&  在前一个命令结束时,若返回值为 true,继续执行下一个命令。
||      在前一个命令结束时,若返回值为 false,继续执行下一个命令。
!      执行 history 列表中的命令。
 
Shell Quoting
一共有三种转义字符,它们实际上也可以看作是shell中的meta:
‘’(单引号):

又叫hard quote,其内部所有的shell meta都会被关掉。注意,hard quote中不允许出现’(单引号)。


“”(双引号):
又叫soft quote,其内部只允许出现特定的shell meta:
       $     用于参数代换
       `      反引号,用于命令代换
       \$    实现美元标志
       \’     实现反引号的文本化(去除反引号的特殊意义)
       \”     实现双引号的文本化(去除双引号的特殊意义)

       \\     实现反斜杠的文本化(去除反斜杠的特殊意义)

       注意,在soft quote中单引号没有特殊意义,就是文本。


\(反斜杠):
 又叫escape,去除其后紧跟的meta或wildcard的特殊意义。
实际上quote的使用就是为了跳过shell对特殊字符的处理。
 
Regular Expression
锚点(anchor):
用以标识 RE 于句子中的位置所在. 常见有:
^     表示句首. 如 ^abc 表示以 abc 开首的句子.
$     表示句尾. 如 abc$ 表示以 abc 结尾的句子.
\<    表示词首. 如 \<abc 表示以 abc 开首的词.
\>    表示词尾. 如 abc\> 表示以 abc 结尾的词.
修饰字符(modifier):
独立表示时本身不具意义, 专门用以修改前一个字元集的出现次数. 常见有:
*     表示前一个字元集的出现次数为0或多次。如ab*c表示a与c之间可有0或多个b存在。
?      表示前一个字元集的出现次数为0或1次。如ab?c表示a与c之间可有0或1个b存在。
+     表示前一个字元集的出现次数为1或多次。如ab+c表示a与c之间可有1或多个b存在。
{n}  表示前一个字元集的出现次数必须为n次. 如ab{3,}c表示 a与c之间必须有3个b存在。
{n,} 表示前一个字元集的出现次数至少为n次. 如ab{3,}c表示a与c之间至少有3个b存在。
{n,m}     表示前一个字元集的出现次数为n到m次. 如ab{3,5}c表示a与c之间有3到5个b存在。
 
总结
总的来说,正是因为shell中的meta、wildcard有时会和command中的meta相同,为了让command中的meta不被shell解析以至于改变,就必须用shell quoting来保证其文字不变性。

 

实例:
[root@redhat script]#ll
总用量 40
-rw-r--r--  1 root root    1 2011/12/06 05:12:25 1
-rwxrwxrwx  1 root root  103 2011/09/22 02:10:07 aa.bak
-rwxr-xr-x  1 root root  121 2011/12/06 06:51:07 aa.sh
drwxr-xr-x  2 root root 4096 2011/11/26 23:27:11 CD
-rwxr-xr-x  1 root root   44 2011/09/22 12:11:21 first.sh
-rwxrwxrwx  1 root root  195 2011/12/06 06:07:48 grade.txt
-rwxrwxrwx  1 root root  303 2011/11/27 03:04:04 list
-rwxrwxrwx  1 root root  101 2011/11/27 03:52:13 nameState
-rwxrwxrwx  1 root root   44 2011/11/27 03:24:34 sedscr
-rwxrwxrwx  1 root root   90 2011/09/21 20:39:22 test.sh
[root@redhat script]#grep aa* aa.sh
[root@redhat script]#
[root@redhat script]#
[root@redhat script]#grep ll* aa.sh     
shopt -s expand_aliases
alias jesse='echo "I am Jesse"'
alias lll='ls -l'
lll /root/y*
[root@redhat script]#grep 'aa*' aa.sh
#/bin/bash
shopt -s expand_aliases
alias jesse='echo "I am Jesse"'
alias lll='ls -l'
aasdfdsf
sdfaads
[root@redhat script]#grep 'll*' aa.sh
shopt -s expand_aliases
alias jesse='echo "I am Jesse"'
alias lll='ls -l'
lll /root/y*
[root@redhat script]#


附:shell脚本的解释过程

 
需要注意的是,double quote中的内容跳过了1-4步和9-10步,single quote中的内容跳过了1-10步。也就是说,double quote只经过参数扩展、命令代换和算术代换就可以送入执行步骤,而single quote直接会被送入执行步骤。而且,无论是double quote还是single quote在执行的时候能够告诉各个命令自身内部是一体的,但是其本身在执行时是并不是命令中文本的一部分。

Lsdetail=”ls –l”
$Lsdetail

执行的就是ls –l,而double quote并不是执行命令的一部分。




理解

1、在不严格区分的情况下shell的解释中,包括:meta(元字符) 与 literal(普通字符),meta包括一些wildcard(通配符)和一些其他的特殊字符。

2、在shell中能处理正则表达式的命令(command)中的解释中也包括有meta(元字符)。

3、若是希望能够将shell中的meta以其文本形式进入command的最终执行形态中,就是希望meta不要被shell解释而被能处理正则表达式的command来解释,就需要用到shell的quoting(转义)来完成的,quoting属于shell中的特殊字符。


下面分别给出shell中的元字符(也就是通配符和一些特殊字符)和command中的元字符


shell中的元字符

一些常用的通配符:

符号

意义

*

代表『 0 个到无穷多个』任意字符

?

代表『一定有一个』任意字符

[ ]

同样代表『一定有一个在括号内』的字符(非任意字符)。例如 [abcd] 代表『一定有一个字符, 可能是 a, b, c, d 这四个任何一个』

[ - ]

若有减号在中括号内时,代表『在编码顺序内的所有字符』。例如 [0-9] 代表 0 到 9 之间的所有数字,因为数字的语系编码是连续的!

[^ ]

若中括号内的第一个字符为指数符号 (^) ,那表示『反向选择』,例如 [^abc] 代表 一定有一个字符,只要是非 a, b, c 的其他字符就接受的意思。

{string1,string2,...} 匹配 sring1 或 string2 (或更多)其一字符串 a{abc,xyz,123}b    a与b之间只能是abc或xyz或123这三个字符串之一。

 



一些常用的特殊字符:

符号

内容

#

批注符号:这个最常被使用在 script 当中,视为说明!在后的数据均不执行

\

跳脱符号:将『特殊字符或通配符』还原成一般字符

|

管线 (pipe):分隔两个管线命令的界定(后两节介绍);

;

连续指令下达分隔符:连续性命令的界定 (注意!与管线命令并不相同)

~

用户的家目录

$

取用变数前导符:亦即是变量之前需要加的变量取代值

&

工作控制 (job control):将指令变成背景下工作

!

逻辑运算意义上的『非』 not 的意思!

/

目录符号:路径分隔的符号

>, >>

数据流重导向:输出导向,分别是『取代』与『累加』

<, <<

数据流重导向:输入导向 (这两个留待下节介绍)

' '

单引号,不具有变量置换的功能

" "

具有变量置换的功能!

` `

两个『 ` 』中间为可以先执行的指令,亦可使用 $( )

( )

在中间为子 shell 的起始与结束

{ }

在中间为命令区块的组合!


IFS -----------由 <space> 或 <tab> 或 <enter> 三者之一组成(我们常用 space )。

CR-----------由 <enter> 产生。

 = ------------设定变量。

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

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



command中的元字符


一些正则表达式中的特殊符号:

特殊符号

代表意义

[:alnum:]

代表英文大小写字符及数字,亦即 0-9, A-Z, a-z

[:alpha:]

代表任何英文大小写字符,亦即 A-Z, a-z

[:blank:]

代表空格键与 [Tab] 按键两者

[:cntrl:]

代表键盘上面的控制按键,亦即包括 CR, LF, Tab, Del.. 等等

[:digit:]

代表数字而已,亦即 0-9

[:graph:]

除了空格符 (空格键与 [Tab] 按键) 外的其他所有按键

[:lower:]

代表小写字符,亦即 a-z

[:print:]

代表任何可以被打印出来的字符

[:punct:]

代表标点符号 (punctuation symbol),亦即:" ' ? ! ; : # $...

[:upper:]

代表大写字符,亦即 A-Z

[:space:]

任何会产生空白的字符,包括空格键, [Tab], CR 等等

[:xdigit:]

代表 16 进位的数字类型,因此包括: 0-9, A-F, a-f 的数字与字符

 


一些常用的基础正则表达式字符:

RE 字符

意义与范例

^word

意义:待搜寻的字符串(word)在行首!
范例:搜寻行首为 # 开始的那一行,并列出行号

grep -n '^#' regular_express.txt

word$

意义:待搜寻的字符串(word)在行尾!
范例:将行尾为 ! 的那一行打印出来,并列出行号

grep -n '!$' regular_express.txt

.

意义:代表『一定有一个任意字符』的字符!
范例:搜寻的字符串可以是 (eve) (eae) (eee) (e e), 但不能仅有 (ee) !亦即 e 与 e 中间『一定』仅有一个字符,而空格符也是字符!

grep -n 'e.e' regular_express.txt

\

意义:跳脱字符,将特殊符号的特殊意义去除!
范例:搜寻含有单引号 ' 的那一行!

grep -n \' regular_express.txt

*

意义:重复零个到无穷多个的前一个 RE 字符
范例:找出含有 (es) (ess) (esss) 等等的字符串,注意,因为 * 可以是 0 个,所以 es 也是符合带搜寻字符串。另外,因为 * 为重复『前一个 RE 字符』的符号, 因此,在 * 之前必须要紧接着一个 RE 字符喔!例如任意字符则为 『.*』 !

grep -n 'ess*' regular_express.txt

[list]

意义:字符集合的 RE 字符,里面列出想要撷取的字符!
范例:搜寻含有 (gl) 或 (gd) 的那一行,需要特别留意的是,在 [] 当中『谨代表一个待搜寻的字符』, 例如『 a[afl]y 』代表搜寻的字符串可以是 aay, afy, aly 即 [afl] 代表 a 或 f 或 l 的意思!

grep -n 'g[ld]' regular_express.txt

[n1-n2]

意义:字符集合的 RE 字符,里面列出想要撷取的字符范围!
范例:搜寻含有任意数字的那一行!需特别留意,在字符集合 [] 中的减号 - 是有特殊意义的,他代表两个字符之间的所有连续字符!但这个连续与否与 ASCII 编码有关,因此,你的编码需要设定正确(在 bash 当中,需要确定 LANG 与 LANGUAGE 的变量是否正确!) 例如所有大写字符则为 [A-Z]

grep -n '[0-9]' regular_express.txt

[^list]

意义:字符集合的 RE 字符,里面列出不要的字符串或范围!
范例:搜寻的字符串可以是 (oog) (ood) 但不能是 (oot) ,那个 ^ 在 [] 内时,代表的意义是『反向选择』的意思。 例如,我不要大写字符,则为 [^A-Z]。但是,需要特别注意的是,如果以 grep -n [^A-Z] regular_express.txt 来搜寻,却发现该档案内的所有行都被列出,为什么?因为这个 [^A-Z] 是『非大写字符』的意思, 因为每一行均有非大写字符,例如第一行的 "Open Source" 就有 p,e,n,o.... 等等的小写字

grep -n 'oo[^t]' regular_express.txt

\{n,m\}

意义:连续 n 到 m 个的『前一个 RE 字符』
意义:若为 \{n\} 则是连续 n 个的前一个 RE 字符,
意义:若是 \{n,\} 则是连续 n 个以上的前一个 RE 字符!
 范例:在 g 与 g 之间有 2 个到 3 个的 o 存在的字符串,亦即 (goog)(gooog)

grep -n 'go\{2,3\}g' regular_express.txt

 


一些常用的扩展的正则表达式字符:

RE 字符

意义与范例

+

意义:重复『一个或一个以上』的前一个 RE 字符
范例:搜寻 (god) (good) (goood)... 等等的字符串。 那个 o+ 代表『一个以上的 o 』所以,底下的执行成果会将第 1, 9, 13 行列出来。

egrep -n 'go+d' regular_express.txt

?

意义:『零个或一个』的前一个 RE 字符
范例:搜寻 (gd) (god) 这两个字符串。 那个 o? 代表『空的或 1 个 o 』所以,上面的执行成果会将第 13, 14 行列出来。 有没有发现到,这两个案例( 'go+d' 与 'go?d' )的结果集合与 'go*d' 相同? 想想看,这是为什么喔! ^_^

egrep -n 'go?d' regular_express.txt

|

意义:用或( or )的方式找出数个字符串
范例:搜寻 gd 或 good 这两个字符串,注意,是『或』! 所以,第 1,9,14 这三行都可以被打印出来喔!那如果还想要找出 dog 呢?

egrep -n 'gd|good' regular_express.txt
egrep -n 'gd|good|dog' regular_express.txt

()

意义:找出『群组』字符串
范例:搜寻 (glad) 或 (good) 这两个字符串,因为 g 与 d 是重复的,所以, 我就可以将 la 与 oo 列于 ( ) 当中,并以 | 来分隔开来,就可以啦!

egrep -n 'g(la|oo)d' regular_express.txt

()+

意义:多个重复群组的判别
范例:将『AxyzxyzxyzxyzC』用 echo 叫出,然后再使用如下的方法搜寻一下!

echo 'AxyzxyzxyzxyzC' | egrep 'A(xyz)+C'

上面的例子意思是说,我要找开头是 A 结尾是 C ,中间有一个以上的 "xyz" 字符串的意思~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值