有时候需要使用正则的非贪婪模式(non-greedy或者叫lazy模式)来搜一些内容,但Macos系统自带的grep无法胜任。
Mac下的grep是BSD系的,不能使用-P参数来使用perl模式。Linux下的GNU grep就可以使用-P参数来支持非贪婪模式。

MacOS自带的grep的示例:

1
2
3
4
5
6
7
8
9
10
$ cat grep_on_macos.txt
carl has a nice car. the car has four wheels.
$
# 支持普通正则
$ grep -o "car.*has" grep_on_macos.txt
carl has a nice car. the car has
$
# 不支持带?的非贪婪模式
$ grep -o "car.*?has" grep_on_macos.txt
$

此处记录两个可行的方法来解决该问题

使用egrep

在Terminal中敲击man egrep, 在man page的Description中可以看到有如下一行描述

1
2
grep is used for simple patterns and basic regular expressions (BREs);
egrep can handle extended regular expressions (EREs).

可以看到Mac默认的grep只支持基本政策表达式,而egrep支持扩展正则表达式

因此在上面的例子中,使用egrep来替代grep就能达到目的。

1
2
3
4
5
6
7
8
9
10
11
12
$ cat grep_on_macos.txt
carl has a nice car. the car has four wheels.
$
# 普通正则表达式没问题
$ egrep -o "car.*has" grep_on_macos.txt
carl has a nice car. the car has
$
# egrep也支持?的非贪婪模式
$ egrep -o "car.*?has" grep_on_macos.txt
carl has
car. the car has
$

Install GNU grep

使用egrep的方法,在偶尔手动操作来查找的时候是可行的。但如果是要在Macos下要运行某个脚本,而脚本中使用了grep的-P参数,此时egrep方法就有局限性,总不能还得改脚本吧。

此时,可以使用Homebrew来安装GNU grep。安装时候也有两种办法

方法一

简单粗暴,Homebrew安装时直接覆盖系统的grep

1
brew install grep --with-default-names

此时,直接会将系统的grep替换为brew安装的GNU grep

方法二

不覆盖系统自带的grep,通过~/.bashrc alias的方式来实现

1
brew install grep

此时,brew安装的GNU grep安装路径为/usr/local/bin/ggrep。注意是ggrep,而不是grep

再通过alias的方式让shell在运行grep的时候运行ggrep, 可以达到同样的效果

1
echo "alias grep='ggrep'" >> ~/.bashrc

更推荐方法二,alias的grep只在自己账号下使用,不会影响系统。运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat grep_on_macos.txt
carl has a nice car. the car has four wheels.
$
# 查看grep的alias
$ alias grep
alias grep='ggrep'
$
# 普通正则表达式没问题
$ grep -o "car.*has" grep_on_macos.txt
carl has a nice car. the car has
$
# 运行的grep也支持?的非贪婪模式
$ grep -P -o "car.*?has" grep_on_macos.txt
carl has
car. the car has
$

留言