grep 文本文件中的数字范围

smc*_*smc 1 shell grep bash zsh

我在文本文件中有以下文本

$ cat test
20180618:
20180619:
20180620:
20180621:
20180622:
20180623:
20180624:
Run Code Online (Sandbox Code Playgroud)

我试图用下面的数字范围进行 grep,

$ grep 201806{19..21} test
grep: 20180619: No such file or directory
grep: 20180620: No such file or directory
grep: 20180621: No such file or directory
Run Code Online (Sandbox Code Playgroud)

我在 ZSH 和 bash 上都遇到了上述错误。似乎 grep 将搜索字符串作为文件。

我试过另一种方式:

$ grep 201806* test       
zsh: no matches found: 201806*
Run Code Online (Sandbox Code Playgroud)

我只在 ZSH 上收到该错误。*在 ZSH 中使用的正确方法是什么,如何告诉 grep 到 grep 的数字范围?

Kus*_*nda 6

是的,默认情况下grep仅将其第一个参数视为正则表达式。

这意味着

grep {1..9} file
Run Code Online (Sandbox Code Playgroud)

扩展到

grep 1 2 3 4 5 6 7 8 9 file
Run Code Online (Sandbox Code Playgroud)

将调用grepwith1作为表达式以在其他操作数中匹配,并且这些其他操作数应为文件名。

你的另一个命令:

grep 201806* test
Run Code Online (Sandbox Code Playgroud)

这将尝试匹配201806*为文件名通配模式。201806当前目录中没有名称以开头的文件,因此zshshell 无法展开模式并显示错误消息no matches found

在其他类似 Bourne 的 shell 中,如果模式没有匹配任何文件名,它将保持未扩展状态并用作带有grep. 表达式201806*作为正则表达式时,匹配20180后跟零个或多个6字符,例如2018066666.

相反,您可能想要构建一个正则表达式来匹配您的范围:

grep -E '201806(19|20|21)' test
Run Code Online (Sandbox Code Playgroud)

或者

grep -E '201806(19|2[01])' test
Run Code Online (Sandbox Code Playgroud)

-E需要已经grep了解|在表达式(交替)(此交替使得它扩展正则表达式)。


您还可以从大括号扩展构造正则表达式:

set -- {19..21}
re=$( IFS='|'; printf '201806(%s)' "$*" )

grep -E "$re" test
Run Code Online (Sandbox Code Playgroud)

这将首先设置的位置参数$1$2并且$3,在该范围的通缉编号。re然后将变量设置为201806(%s)whereprintf将替换%s为由 分隔的这些数字|

grep调用将201806(19|20|21)用作正则表达式。