1、前言
最近因经常需对基因组注释文件gff3的基因id替换或更改,需要用到正则表达式。资料里面都提到:*匹配前面的子表达式0次或任意多次。我当时就纳闷,*到底是表示的是匹配的次数还是可以匹配任意字符呀?因为印象中,*也可以匹配任意字符。
后面才弄明白自己混淆了正则表达式与通配符,*在正则表达式和通配符中的含义是不一样的。
类似的还有字符:?
2、正则表达式与通配符使用场景
总结就是:正则表达式主要用于shell脚本(正则表达式主要用来匹配文件中的字符串,主要操作有grep、awk、sed。简单来说),而通配符主要用于shell命令行(命令行ls、find、cp、mv等)。
3、正则表达式与通配符具体的使用区别
3.1通配符的基本用法
通配符主要用于shell命令行中。常见的匹配规则有:
ls *
会列出当前目录下所有文件,*
匹配了所有的文件名,而ls *a
匹配所有a开头的文件。
需要注意的是,如果当前目录下有目录名匹配成功,会列出该目录下所有文件
*
可以代替任意个数字符,?
只能代替一个。
通配符主要用法
通配符 含义 举例
* 匹配0或多个任意字符 a*匹配a开头的任意文件
? 匹配任意单个字符 a?.txt可以匹配ab.txt,ac.txt,但是不能匹配abc.txt
\] 匹配括号中任意字符
\[abc\].txt可以匹配a.txt 、b.txt、 c.txt
\[!\] 匹配不在括号中的任意字符 \[!abc\]\*可以匹配不宜abc开头的任意文件
\[a-z\] 匹配a-z的任意单个字符,只能用于查找文件不能用于创建文件 \[a-z\]\*匹配a-z开头的任意文件
{a,b,z} 逗号分隔表示单个字符,可用于创建和查找文件 {a,b,z}\*表示以a或b或z开头的任意文件
{a..z} ..分隔表示连续字符,表示范围 {a..z}\*表示任意小写字母开头的文件
特别需要说明的是:
由于上面表中的一些字符,如\*?\[\]等字符具有特殊的含义(用法),例如,\*并不是代表这个字符本身,而是代表任意字符,因此如果需要匹配\*本身,需要转义。转义用\\表示,如
\\\*表示\*本身,\\\*abc 可以匹配字符串 "\*abc"
**3.2 shell Meta字符(元字符)**
shell 除了有通配符之外,还有一系列自己的其他特殊字符。
|------|-------------------------------------------------------|
| 字符 | 说明 |
| IFS | 由 \ 或 \ 或 \ 三者之一组成(我们常用 space ) |
| CR | 由 \ 产生 |
| = | 设定变量 |
| $ | 取变量值或取运算值 |
| \> | 重定向 stdout |
| \< | 重定向 stdin |
| \| | 管道符号 |
| \& | 重导向 file descriptor ,或将命令置于背景执行 |
| ( ) | 将其内的命令置于 nested subshell 执行,或用于运算或命令替换 |
| { } | 将其内的命令置于 non-named function 中执行,或用在变量替换的界定范围 |
| ; | 在前一个命令结束时,而忽略其返回值,继续执行下一个命令 |
| \&\& | 在前一个命令结束时,若返回值为 true,继续执行下一个命令 |
| \|\| | 在前一个命令结束时,若返回值为 false,继续执行下一个命令 |
| ! | 运算意义上的非(not)的意思 |
| # | 注释,常用在脚本中 |
| \\ | 转移字符,去除其后紧跟的元字符或通配符的特殊意义 |
**3.3 正则表达式的基本用法**
正则表达式主要用于shell脚本中。常见用法如下:
正则表达式的主要用法
元字符 含义 用法举例
() 表示一个字表达式,括号内是一个整体(配合sed命令,则打印括号中的内容)
\* 前一个子表达式或字符匹配0或任意多次
ab\*可以匹配a、ab、abb、abbb等
h(ab)\*可以匹配h或hab或habab
? 前一个子表达式或字符匹配0或1次 h(ab)\*可以匹配h或hab,不能匹配habab
+ 前一个子表达式1次或以上,扩展正则表达式 ----\\(\[0-9\]\\+\\)---"\[0-9\]\\+"表示一串数字
. 匹配出换行符\\n之外的任意单个字符
\[\] 匹配括号中任意一个指定字符,只匹配一个字符 \[aeiou\]可以匹配google中的o e
\[\^\] 匹配不再括号中的任意一个字符
\^ 匹配行首(当不位于\[\]内时) \^hello匹配hello开头的字符串
$ 匹配行尾
\\ 转义字符,取消特殊含义 \\可以匹配字符\*,此时\*不再表示匹配次数
{n} 表示前面的字符恰好n次
{n,} 表示前面的字符最少出现n次
{n,m} 表示前面的字符出现n\~m次
\\1 引用第一个左括号以及与之对应的右括号所包括的所有内容,\\2同理
同通配符的规则,一样,匹配上面表中的特殊字符(元字符)时,也需要转义:
例如\\\*表示\*这个字符本身,次数\*不再表示前面的字符可以出现的次数为任意次。
\\ ----正则表达式中的反斜杠的用法
字符 描述
\\b 匹配一个单词边界,也就是指单词和空格间的位置。例如,"er\\b"可以匹配"never"中的"er",但不能匹配"verb"中的"er"。
\\B 匹配非单词边界。"er\\B"能匹配"verb"中的"er",但不能匹配"never"中的"er"。
\\cx 匹配由x指明的控制字符。例如,\\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的"c"字符。
**\\d 匹配一个数字字符。等价于\[0-9\]** 。
\\D 匹配一个非数字字符。等价于\[\^0-9\]。
\\f 匹配一个换页符。等价于\\x0c和\\cL。
\\n 匹配一个换行符。等价于\\x0a和\\cJ。
\\r 匹配一个回车符。等价于\\x0d和\\cM。
**\\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于\[ \\f\\n\\r\\t\\v\]。**
\\S 匹配任何非空白字符。等价于\[\^ \\f\\n\\r\\t\\v\]。
\\t 匹配一个制表符。等价于\\x09和\\cI。
\\v 匹配一个垂直制表符。等价于\\x0b和\\cK。
\\w 匹配包括下划线的任何单词字符。等价于"\[A-Za-z0-9_\]"。
\\W 匹配任何非单词字符。等价于"\[\^A-Za-z0-9_\]"。
\\xn 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,"\\x41"匹配"A"。"\\x041"则等价于"\\x04\&1"。正则表达式中可以使用ASCII编码。.
\\num 向后引用(back-reference)一个子字符串(substring),该子字符串与正则表达式的第num个用括号围起来的子表达式(subexpression)匹配。其中num是从1开始的正整数,其上限可能是99。例如:"(.)\\1"匹配两个连续的相同字符。
\\n 标识一个八进制转义值或一个向后引用。如果\\n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n为一个八进制转义值。
\\nm 标识一个八进制转义值或一个向后引用。如果\\nm之前至少有nm个获得子表达式,则nm为向后引用。如果\\nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则\\nm将匹配八进制转义值nm。
\\nml 如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。
\\un 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\\u00A9匹配版权符号
**4.awk print与printf的差别**
awk中如果输出字符的话,有两种处理方式。printf和print,两种方式存在着不同,下面简要的说明下。
printf:可以自定义输出的模式,另外输出内容之后不自动换行
print:输出内容之后自动换行
example:
file
11111_22222_33333_44444_55555_66666
awk -F'_' '{for(i=1;i\<=NF;i++)print $i}' file
11111
22222
33333
44444
55555
66666
awk -F'_' '{for(i=1;i\<=NF;i++)printf $i}' file
111112222233333444445555566666
所以可以看出,print输出一个内容之后,自动换行,但是printf不会这样,另外如果我们需要在处理文本的过程中输出换行符的话,可以print "",输出一个空字符就表示输出了一个换行符
参考来源:
[正则表达式与通配符 -- \*?在正则表达式与通配符中的区别_正则 \*?-CSDN博客](https://blog.csdn.net/weixin_43354152/article/details/130918302#:~:text=%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%BB%E8%A6%81%E7%94%A8%E6%9D%A5%E5%8C%B9%E9%85%8D%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%8C%E4%B8%BB%E8%A6%81%E6%93%8D%E4%BD%9C%E6%9C%89grep%E3%80%81awk%E3%80%81sed%E3%80%82%20%E7%AE%80%E5%8D%95%E6%9D%A5%E8%AF%B4%EF%BC%8C%E9%87%8D%E7%82%B9%E5%9C%A8%E4%BA%8E%20%E6%93%8D%E4%BD%9C%E6%96%87%E4%BB%B6%E7%9A%84%E5%85%B7%E4%BD%93%E5%86%85%E5%AE%B9%EF%BC%8C%E4%B8%BB%E8%A6%81%E7%94%A8%E4%BA%8Eshell%E8%84%9A%E6%9C%AC%E4%B8%AD%20%E3%80%82%20%E9%80%9A%E9%85%8D%E7%AC%A6%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%EF%BC%9A%20%E9%80%9A%E9%85%8D%E7%AC%A6%E4%B9%9F%E5%8F%AB%E6%96%87%E4%BB%B6%E5%90%8D%E6%9B%BF%E6%8D%A2%EF%BC%8C%E5%9B%A0%E6%AD%A4%E4%B8%BB%E8%A6%81%E6%98%AF%E7%94%A8%E6%9D%A5,%E5%8C%B9%E9%85%8D%E6%96%87%E4%BB%B6%E5%90%8D%E5%B9%B6%E8%BF%9B%E8%A1%8C%E7%9B%B8%E5%85%B3%E7%9A%84%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%B8%BB%E8%A6%81%E5%9C%A8shell%E5%91%BD%E4%BB%A4%E8%A1%8C%E4%B8%AD%E4%BD%BF%E7%94%A8%20%E3%80%82%20%E5%B8%B8%E8%A7%81%E7%9A%84%E6%93%8D%E4%BD%9C%E6%9C%89%EF%BC%9A%20ls%E3%80%81find%E3%80%81cp%E3%80%81mv%E7%AD%89%E3%80%82%20%E6%80%BB%E7%BB%93%E5%B0%B1%E6%98%AF%EF%BC%9A%20%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%BB%E8%A6%81%E7%94%A8%E4%BA%8Eshell%E8%84%9A%E6%9C%AC%EF%BC%8C%E8%80%8C%E9%80%9A%E9%85%8D%E7%AC%A6%E4%B8%BB%E8%A6%81%E7%94%A8%E4%BA%8Eshell%E5%91%BD%E4%BB%A4%E8%A1%8C%20%E3%80%82 "正则表达式与通配符 -- *?在正则表达式与通配符中的区别_正则 *?-CSDN博客")
[通配符与正则表达式_通配符和正则表达式-CSDN博客](https://blog.csdn.net/zgqxiexie/article/details/51184602 "通配符与正则表达式_通配符和正则表达式-CSDN博客")
[通配符和正则的区别_通配符和正则符的区别-CSDN博客](https://blog.csdn.net/blackfwhite/article/details/80382849 "通配符和正则的区别_通配符和正则符的区别-CSDN博客")