背景
在linux使用过程中,经常需要查找文件,对命令中的通配符 pattern 和正则表达式的区分不是很清楚。有必要好好研究一下。
1 扫盲
通配符和正则表达式
当在使用命令行时,有很多时间都用来查找你所需要的文件,如 ls find 等。 shell 提供了一套完整的字符串模式匹配规则,或者称之为元字符,当 shell 遇到上述字符时,就会把它们当作特殊字符,而不是文件名中的普通字符,这样用户就可以用它们来匹配相应的文件名,我理解这可以称为通配符。
通配符与正则表达式是有区别的,简单来说:通配符是用来通配的,正则表达式是用来匹配字符串的;
通配符是shell自带的用于匹配文件名的工具,多用在文件名上,比如查找find,ls,cp 等等,而正则表达式则需要特定命令的支持才可以使用,如:grep、sed和awk(号称linux三剑客)、vi/vim、perl等,这些都是处理文本的工具。
其次,shell对通配符与正则表达式的处理也有不同,“ ”内一般为通配符(是shell本身提取处理),‘ ’内一般为正则表达式(shell会将其中的数据传递给其它命令处理)。
通配符
常见元字符:
*:匹配零或多个任意字符?:匹配任意单个字符[]:指定中括号内的多个字符,如:[rwc]或[r,w,c]都行[^]或[!]:除了中括号内字符外匹配任一个字符
引用以下模式要在外面再套一个[],tr命令则不用(这是规定吗?)
[:digit:]:匹配任意一个数字[:lower:]:任意小写字符[:upper:]:任意大写字符[:alpha:]:任意大小写字母[:alnum:]:任意一个字母或数字[:space:]:一个空格[:punct:]:标点符号
正则表达式
这里不具体介绍正则表达式,只是说一下和通配符的区别
首先通配符没有次数匹配
*:匹配前面的字符零次或多次.:匹配任意一个字符?:前面的字符零次或一次,基本正则是?+:前面的字符至少一次,基本正则是+[]:和通配符完全一样[^]:和通配符一样,但是没有[!]的写法
2 通配符详细介绍
测试数据
touch a a6.log abc.log ac.txt b c c5.txt x.log a
* 代表任意多个字符
- 例:查询以
.log结尾的文件ll *.log
? 代表任意单个字符
- 例:只查询
a、b、cll ?
[] 代表 [ 和 ] 之间的某一个字符,比如[0-9]可以代表0-9之间的任意一个数字,[a-za-z]可以代表a-z和a-z之间的任意一个字母,字母区分大小写。
- 例:只查询字母文件
ll [a-za-z] - 例:查询以
.log结尾且.log前只有两个字符的文件且第二个字符是数字ll ?[0-9].log
^ 表示匹配结果取反的意思,注意这个通配符必须要在[]中使用
- 例:查询不是以
.txt结尾的文件ll *[^txt]*
{} 表示符合括号内包含的多个文件
- 例:查询
.log和.txt结尾的文件ll {*.log,*.txt}
注意: .这个符合比较特殊,如果匹配的条件加上了该符合那么说明查询结果文件就包含带.的文件
例如前面的^的例子,如果我这样查询ll *.[^txt]*,那么结果就不一样了
删除操作
- 例如:删除
a、b、c和以.txt结尾的文件
rm -f {[abc],*.txt}当然既然可以查询当然也可以使用通配符匹配的方式进行移动文件,如果需要在存在很多文件的文件夹中移动某些类型的文件那么使用通配符匹配的效率就显而易见了;当时通配符的使用技巧不单单只有这些,有空的可以多去研究。
3 实例
*匹配文件名中的任何字符串,包括空字符串。?匹配文件名中的任何单个字符。[...]匹配[ ]中所包含的任何字符。[!...]匹配[ ]中非感叹号!之后的字符。和^的效果一样
如:
5*5开头的所有字符串*55结尾的所有字符串*5?以5为倒数第二个字符的字符串[0-9]所有以数字的字符[1,2]1或者2[!0-9]不是数字的字符ls /etc/[!a-n]*.conf列出/etc/目录中不是以字母a到n开头的,并且以.conf结尾的文件ls /etc/[a-n]*.conf列出/etc/目录中以字母a到n开头的,并且以.conf结尾的文件ls /bin/[ck]*列出以 c或k开头的文件名
4 正则表达式详细介绍
正则表达式(也称为“regex”或“regexp”)是一种用来描述文本模式的特殊语法。
在 linux 系统上,正则表达式通常被用来查找文本的模式,以及对文本流执行“搜索-替换”操作以及其它功能。
简单字串
$ grep bash /etc/passwd operator:x:11:0:operator:/root:/bin/bash root:x:0:0::/root:/bin/bash ftp:x:40:1::/home/ftp:/bin/bash
在上面的命令中,grep 的第一个参数是一个正则表达式;第二个参数是一个文件名。grep 读取 /etc/passwd 中的每一行并对它应用简单子串正则表达式 bash 来查找匹配项。如果找到一个匹配项,那么 grep 打印出整行;否则,忽略该行。
理解简单子串
一般来说,如果您正在搜索一个子串,那么您可以不提供任何“特殊”字符,而只是逐字地指定文本。只有在子串包含 +、.、*、[、] 或 /(在这样的情况下,这些字符需要用引号括起来并在它们的前面使用反斜杠)才需要做特殊的事情。
下面是简单子串正则表达式几个其它示例:
tmp (扫描查找文字串 tmp) “\[box\]”(扫描查找文字串 [box]) “\*funny\*”(扫描查找文字串 *funny*) “ld\.so”(扫描查找文字串 ld.so)
元字符
使用正则表达式,可以利用元字符来执行比我们至今已研究过的示例复杂得多的搜索。这些元字符中的一个是 .(点),它与任何单个字符匹配:
$ grep dev.hda /etc/fstab /dev/hda3 reiserfs noatime,ro 1 1 /dev/hda1 /boot reiserfs noauto,noatime,notail 1 2 /dev/hda2 swap sw 0 0 #/dev/hda4 /mnt/extra reiserfs noatime,rw 1 1
在本示例中,文字文本 dev.hda 没有出现在 /etc/fstab 中的任何一行中。但是,grep 扫描这些行时没有查找文字 dev.hda 字符串,而是查找 dev.hda 模式。请记住 . 将与任何单个字符相匹配。正如您看到的,. 元字符在功能上等价于 glob 扩展中 ? 元字符的工作原理。
使用 []
如果我们希望与比 . 更具体一点地来匹配字符,那么我们可以使用 [ 和 ](方括号)来指定要匹配的字符子集:
$ grep dev.hda[12] /etc/fstab /dev/hda1 /boot reiserfs noauto,noatime,notail 1 2 /dev/hda2 swap swap sw 0 0
[\u4e00-\u9fa5] : 表示任意一个汉字
正如您看到的,这个特殊语法的作用与glob文件名扩展中的 [] 相同。
使用 [^]
通过使 [ 后面紧跟一个 ^,您可以使方括号中的意思相反。在本例中,方括号将与未列在方括号内的任意字符匹配。同样,请注意我们在正则表达式中使用 [^] ,而在 glob 中使用 [!] :
$ grep dev.hda[^12] /etc/fstab /dev/hda3 reiserfs noatime,ro 1 1 /dev/hda4 /mnt/extra reiserfs noatime,rw 1 1
区别语法
注意下面一点很重要:方括号内部的语法根本不同于正则表达式其它部分中的语法。
例如,如果在方括号内放置一个 . ,那么它允许方括号与文字 . 匹配,就象上面示例中的 1 和 2。比较起来,除非有\ 作为前缀,否则方括号外面的文字 . 被解释为一个元字符。通过输入如下命令,我们可以利用这一事实来打印 /etc/fstab 中包含文字串 dev.hda 的所有行的列表:
$ grep dev[.]hda /etc/fstab
或者,我们也可以输入:
$ grep "dev\.hda" /etc/fstab
这两个正则表达式都不可能与您的 /etc/fstab 文件中的任何行相匹配。
*元字符
某些元字符本身不匹配任何字符,但却修改前一个字符的含义。一个这样的元字符是 * (星号),它用来与前一个字符的零次或者多次重复出现相匹配。
这里是一些示例:
ab*c(与abbbbc匹配但不与abqc匹配)ab*c(与abc匹配但不与abbqbbc匹配)ab*c(与ac匹配但不与cba匹配)b[cq]*e(与bqe匹配但不与eb匹配)b[cq]*e(与bccqqe匹配但不与bccc匹配)b[cq]*e(与bqqcce匹配但不与cqe匹配)b[cq]*e(与bbbeee匹配).*(与任何字符串匹配)foo.*(与以foo开始的任何字符串相匹配)ac行与正则表达式ab*c相匹配,因为星号也允许前面的表达式b出现零次。请注意解释*正则表达式元字符所用的方法与解释* glob字符的方法根本不同。
行的开始和结束
我们在这里要详细描述的最后几个元字符是 ^ 和 $ 元字符,它们用来分别与行的开始和结束相匹配。通过在正则表达式开始处使用一个 ^ ,您可以将您的模式“锚定”在行的开始。
在下面的示例中,我们使用 ^# 正则表达式来与以 # 字符开始的任何行相匹配:
$ grep ^# /etc/fstab # /etc/fstab: static file system information. #
完整行正则表达式
可以组合 ^ 和 $ 来与完整的行相匹配。
例如,下面的正则表达式将与以 # 字符开始并以. 字符结束的行相匹配,在其中间可以有任意多个其它字符:
$ grep '^#.*/.$' /etc/fstab # /etc/fstab: static file system information.
在上面的示例中,我们用单引号将我们的正则表达式括起来以阻止 shell 解释 $ 。
在不使用单引号的情况下,grep 甚至没有机会查看 $,$ 就从我们的正则表达式上消失了。
正则总结
元字符
.:小数点可以匹配除\n以外的任意一个字符。如果要匹配包括\n在内的所有字符,一般用[\s\s],或者是用.加(?s)匹配模式来实现。[abc]:匹配方括号中的任意一个字符。可以使用-表示字符范围,如[a-z0-9]匹配小写字母和阿拉伯数字。[^abc]:在方括号内开头使用^符号,表示匹配除方括号中字符之外的任意字符。|: 表示或\d匹配阿拉伯数字,等同于[0-9]。\d匹配阿拉伯数字之外的任意字符,等同于[^0-9]。\x匹配十六进制数字,等同于[0-9a-fa-f]。\x匹配十六进制数字,等同于[^0-9a-fa-f]。\w匹配单词字母,等同于[0-9a-za-z_]。\w匹配单词字母之外的任意字符,等同于[^0-9a-za-z_]。\t匹配<tab>字符。\s匹配空白字符,等同于[ /t]。\s匹配非空白字符,等同于[^ /t]。\a所有的字母字符. 等同于[a-za-z]\l小写字母[a-z]\l非小写字母[^a-z]\u大写字母[a-z]\u非大写字母[^a-z]
表示数量的元字符
元字符 说明
*匹配0-任意个\+匹配1-任意个\?匹配0-1个\{n,m\}匹配n-m个\{n\}匹配n个\{n,\}匹配n-任意个\{,m\}匹配0-m个
换行符 说明
\r,\n回车和换行\\匹配\\^,\$,\.匹配^$.
以下字符在匹配其本身时,通常需要进行转义。
在实际应用中,根据具体情况,需要转义的字符可能不止如下所列字符 : $ ^ { [ ( | ) * + ? \
表示位置的符号
$匹配行尾^匹配行首\<匹配单词词首\>匹配单词词尾\b匹配单词边界
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论