![在 grep 中使用简单的正则量词表达式](https://linux22.com/image/45437/%E5%9C%A8%20grep%20%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%AE%80%E5%8D%95%E7%9A%84%E6%AD%A3%E5%88%99%E9%87%8F%E8%AF%8D%E8%A1%A8%E8%BE%BE%E5%BC%8F.png)
有谁知道为什么ls | xargs -n 1 basename | grep -E '[0-9]{1}'
不只显示 0-9 之间的单个数字的出现?
例如,如果我有:
touch 1
touch 22
touch 333
touch test_file
如果我跑ls | xargs -n 1 basename | grep -P '[0-9]{1}'
:
我列出了 1、22 和 333 个文件。
如果我跑ls | xargs -n 1 basename | grep -P '[0-9]{2}'
:
我列出了 22 和 333 个文件。
我希望 {2} 仅显示 22 文件。
答案1
我认为你期待的事情与正在发生的事情不同的原因是你正在采取
[0-9]{n}
意思是仅匹配 [0-9] 中出现的 n 个字符并丢弃其余的,而它的作用是在 [0-9] 中找到 n 个出现的字符并将其称为匹配。所以在
[0-9]{1}
它会准确地找到任何一次匹配 [0-9] 的内容,因此 1 匹配,然后在检查 22 时,它会在前 2 处停止并认为它是匹配的,而不查看其余的。对于 333 也是如此。如果您指定
[0-9]{2}
它不会匹配 1,而是匹配 22 场比赛,然后是 333 场比赛中的 33 场比赛,所以它会抓住它。
正如 slm 所说,单词边界是这里的关键。您的问题中既有 -P 也有 -E 风格的 grep 正则表达式匹配。您可以将 GNU \< 和 \> 与 -E 一起使用,如下所示:
ls | xargs -n 1 basename | grep -E '\<[0-9]{1}\>'
或 \b 与 -E 或 pcre 匹配 -P 如下
ls | xargs -n 1 basename | grep -P '\b[0-9]{1}\b'
答案2
用于grep -x
查找精确匹配,而不是在行内查找匹配。
grep foo
查找包含 的行foo
,同时grep -x foo
查找包含是 foo
。
同样,grep -E '[0-9]{1}'
(与 相同grep '[0-9]'
)查找包含一位数字的行。grep -xE '[0-9]{1}'
查找由一位数字组成的行。
使用 GNU grep
,您可以使用--color
或-o
选项来查看正在匹配的内容,尽管它会显示所有匹配项。
答案3
这是因为前两个字符与333
正则表达式匹配,因此整行匹配。
如果你想避免这种情况,你可以使用:
(^|[^0-9])[0-9]{2}([^0-9]|$)
答案4
如果将示例的内容放入文本文件中,您可以看到为什么grep
匹配它:
$ grep -E '[0-9]{1}' file.txt
touch 1
touch 22
touch 333
您可以使用单词边界 ( -w
) 来表明grep
您只想匹配正则表达式 ( \<REGEX\>
) 的单个单词,而不是恰好匹配它的任何字符串:
$ grep -Ew '\<[0-9]{1}\>' file.txt
touch 1
$ grep -Ew '\<[0-9]{2}\>' file.txt
touch 22
$ grep -Ew '\<[0-9]{3}\>' file.txt
touch 333
和\<
告诉边界在哪里\>
。grep
这会强制grep
匹配显式单词(例如 1),但不匹配字符串(例如 11、111 或 aa11aa),因为这些字符串中的正则表达式不包含在单词边界内。