shell和正则表达式中的星号(*)

时间:2022-12-11 21:34:16

写在最前面:最近初学sed及正则表达式,对只包含单独一个星号(*)的正则表达式的含义产生了困惑,因而对此问题做了肤浅的探究,欢迎讨论指正。下面进入正题。


在shell和正则表达式中,星号(*)的含义是不一样的。

在shell中,星号(*)除了表示乘法运算符外,另一个重要含义就是通配符(globbing),用来匹配指定目录下的所有文件包括文件夹(不包括影藏文件及文件夹)。

nani@debian:~/test$ ls -al

total 12

drwxr-xr-x  2 nani nani 4096 Jan 16 11:17 .

drwxr-xr-x 16 nani nani 4096 Jan 16 10:00 ..

-rw-r--r--  1 nani nani    0 Jan 16 10:35 *

-rw-r--r--  1 nani nani   11 Jan 16 10:56 text

-rw-r--r--  1 nani nani    0 Jan 16 11:17 .text

-rw-r--r--  1 nani nani    0 Jan 16 10:35 *text

-rw-r--r--  1 nani nani    0 Jan 16 10:36 *text*

-rw-r--r--  1 nani nani    0 Jan 16 10:35 text*

nani@debian:~/test$ echo *

* text *text *text* text*

我们还有如下的用法:

1、    显示文件名以“t”开头的文件

nani@debian:~/test$ ls t*

text  text*

2、    显示文件名以“t”结尾的文件

nani@debian:~/test$ ls *t

text  *text

3、    显示文件名中包含“t”的文件

nani@debian:~/test$ ls *t*

text  *text  *text*  text*

这里的星号(*)以一种伪正则表达式的形式出现,但显然它不是正则表达式。星号(*)在这里给我们的感觉就像它可以表示任意字符串包括空串。实际上shell只是对星号(*)做了文件名扩展,shell对星号(*,通配符)只做文件名扩展。这种感觉并不影响我们使用,甚至在这种情况下我们就是靠这种感觉在使用星号(*),似乎没发生什么错误。至于在这里shell到底是如何解释星号(*)的,我并不清楚,这并没有像上面提到的“echo *”那样容易理解,还望高人指点迷津。那么,基于这种感觉我们再来看个例子

nani@debian:~/test$ ls | grep *

结果并没有像我们感觉的那样——列出当前目录的所有文件,它什么也没输出。实际上,这条命令在执行时会被扩展为“ls | grep * text *text *text* text*”,即在文件“text”、“*text”、“*text*”、“text*”中查找包含“*”的行,管道也没有起到预期的作用。似乎发生了什么“错误”。因此,明确星号(*)在shell中的含义才能帮助我们正确地在shell中使用星号(*)。

防止这种扩展可使用引号(单引号或双引号均可)或反斜杠,如查看文件名以“*”开头的文件

nani@debian:~/test$ ls \**

*  *text  *text*

nani@debian:~/test$ ls '*'*

*  *text  *text*

nani@debian:~/test$ ls "*"*

*  *text  *text*

在正则表达式中,星号(*)表示匹配前一个字符零次或多次。

在这里建立一个示例文档,并使用sed作为验证正则表达式的工具,以此举几个例子。

nani@debian:~/test$ cat text

^

*

a

举个简单的例子

nani@debian:~/test$ sed -n '/^a*/p' text

^

*

a

结果打印出了所有的行,这点很容易理解。

在正则表达式中单独使用一个星号(*)会怎么样呢?

nani@debian:~/test$ sed -n '/*/p' text

*

结果打印出了第二行,这表示单独使用一个星号(*)时会将它转意为普通字符吗?我们将星号(*)转意了再试一下。

nani@debian:~/test$ sed -n '/\*/p' text

*

结果如预期,打印出了第二行。我们再看一个例子

nani@debian:~/test$ sed -n '/^*$/p' text

*

结果打印出了第二行。只打印了第二行而没有打印第一行,说明星号(*)被作为普通字符匹配了。我们再试一个奇怪的例子

nani@debian:~/test$ sed -n '/**/p' text

^

*

a

结果打印出了所有的行。很显然这个正则表达式匹配的是包含零个或多个星号(*)的行。

至此我们可以得出一个结论,在正则表达式中,当星号(*)前面没有字符或是一个元字符时,这个星号(*)会被自动当做普通字符来处理。

这个结论不一定正确。这样的结果也许是sed造成的。我看了些关于正则表达式的资料,也在网上问了些人,对于单独一个星号(*)在正则表达式中的含义都没有明确说明。暂时以此结论继续学习并给具有相同疑惑的同学一点启发和帮助。


写在最后:庆祝第一篇博文完成。。。