树莓派创客:手把手教你玩转人工智能
上QQ阅读APP看书,第一时间看更新

1.4.3 正则表达式

在介绍完这些指令的基本功能之后,我们在这里对正则表达式做一个入门的讲解。如果你对这一部分不是特别感兴趣,可以暂时跳过,这将不会对你的后续学习有任何影响。

为什么要使用正则表达式呢?正则表达式被我们用来匹配一定的文本模式。更具体地说,它可以被用来处理一类特定的文件。举个比较简单的例子,你想要处理文件夹下所有的txt文件,那么你可以使用*.txt这样的表达式来匹配所有的文本文件,使得同时处理大量的文件变成非常简单的一件事情。

接下来介绍一下基本的语法。鉴于篇幅的限制,不可能做原理上的详细讲解,但会尝试以一种简单易懂的方式介绍清楚基本的语法。

正则表达式中的匹配主要依赖于特殊字符,在Linux命令行下的这种正则表达式语法下,.*[]^${}\+?|()被定义为特殊字符。碰到了一个问题,如果想要匹配的文本里本身就包含这些特殊字符怎么办呢?

答案很简单,你只需要把这些特殊字符进行转义,而转义的工具本身也是特殊字符\。接下来在讲解示例的过程中会用到一个命令awk。awk是Linux系统上非常流行的行处理器,它的特点是一行一行地处理数据,然后进行处理化的输出。

请看一个简单的示例:

      $ awk '{print $0}' /etc/passwd

这条指令的意思是原封不动地打印/etc/passwd的内容。$0代表整行内容。再看下面的示例:

      $ awk '{print " "}' /etc/passwd

这条指令的意思是打印与/etc/passwd具有相同行数的空行。从这两条语句的输出行为可以看出awk按行处理文件的特性。在一行一行获取到文本内容后,awk提供了很多处理的相关功能,在这里我们就不进行介绍了,因为awk并不是这里讲解的重点。

接下来回到正则表达式的讲解部分。下面的指令展示了该如何匹配特殊字符:

      $ echo "\ is a special character" | awk '/\\/{print $0}'

在这里我们用\\转义\符号。这里的//表示awk里的匹配代码块,后面这句awk的意思可以理解为输出匹配成功的所有整行。

因为//也有对应的特殊含义,所以也需要转义,示例如下:

      $ echo "3 / 2" | awk '/\//{print $0}'

接下来我们讲解正则表达式里的其他一些问题。你可能会在实际使用中碰到这样的情况,一个单词在句子中多次出现,但你只想匹配那种单词在开头出现的模式,那么你需要用到^符号,它匹配的不是文本,而是位置(这在一开始可能难以理解,你需要想清楚这里位置的含义)。举例来说:

      $ echo "welcome to likegeeks website" | awk '/^likegeeks/{print $0}'

没有对应的输出,而

      $ echo "likegeeks website" | awk '/^likegeeks/{print $0}'

输出likegeeks website。

接下来是匹配的重头戏“.”符号。“.”符号可以匹配除了空字符串外的所有字符,比如:

      $ cat myfile
      this is a test
      This is another test
      And this is one more
      start with this

$ awk '/.st/{print $0}' myfile

输出:

      this is a test
      This is another test

如果你不想匹配所有的字符,而仅仅是几个特定的字符,可使用[]符号,例如:

      $ awk '/[oi]th/{print $0}' myfile

输出如下:

      this is a test
      This is another test

我们甚至可以反向选择,排除对应的字符,示例如下:

      $ awk '/[^oi]th/{print $0}' myfile

这样会排除有o和i出现的情况。

使用-字符可以表示范围,示例如下:

      $ awk '/[e-p]st/{print $0}' myfile

最后看一看“*”符号。在正则表达式里,它有不太一样的含义,这一点在使用的时候千万不要混淆。“*”在bash里有着与刚才“.”类似的含义,但可以匹配多个字符;而在正则表达式里,它并不匹配字符,而是表示一个模式可以重复多次或零次。

      $ echo "st" | awk '/s[ae]*t/{print $0}'

输出st。

      $ echo "awwwwwk" | awk '/aw*k/{print $0}'

输出awwwwwk。