【问题标题】:How can I make grep do a "word match", but without periods being treated as a word separator?如何让 grep 进行“单词匹配”,但不将句点视为单词分隔符?
【发布时间】:2021-06-29 11:14:37
【问题描述】:

我有一个如下所示的文件:

5.3.236.113681.2225191122.986.3705653211.104    4
5.3.236.113681.2225191122.986.3705653211.104.3402  45
5.3.236.0.1.20549687.20.93.9.2.234266672113.4455  2
5.3.236.113681.5829104.986.3705653211.119    8
5.3.236.2.01107.50.01.24.48685.30000018053113560818700000112 172

基本的 grep 将显示这些结果;它显示了一个我不想要的附加匹配项。

$ grep 5.3.236.113681.2225191122.986.3705653211.104 test.txt
5.3.236.113681.2225191122.986.3705653211.104    4
5.3.236.113681.2225191122.986.3705653211.104.3402  45

我尝试 greping 寻找“固定字符串”;它显示了一个我不想要的附加匹配项。

$ grep -F 5.3.236.113681.2225191122.986.3705653211.104 test.txt
5.3.236.113681.2225191122.986.3705653211.104    4
5.3.236.113681.2225191122.986.3705653211.104.3402  45

我尝试 greping 只是为了匹配;它显示了一个我不想要的附加匹配项。

$ grep -w 5.3.236.113681.2225191122.986.3705653211.104 test.txt
5.3.236.113681.2225191122.986.3705653211.104    4
5.3.236.113681.2225191122.986.3705653211.104.3402  45

这行得通,但从技术上讲,它似乎是在寻找我想要的字符串加上空格,这似乎更像是一种解决方法,而不是专门针对我想要的东西。

$ grep "5.3.236.113681.2225191122.986.3705653211.104[[:space:]]" test.txt
5.3.236.113681.2225191122.986.3705653211.104    4

有效的问题是所需的字符串末尾可能没有空格,它可能在前面有空格,如下所示:

4   5.3.236.113681.2225191122.986.3705653211.104
45  5.3.236.113681.2225191122.986.3705653211.104.3402

以前有效的命令在格式稍有不同的列表上无效。

我可以简单地写grep "[[:space:]]5.3.236.113681.2225191122.986.3705653211.104,但我不想为每个这样的小差异重新编写 grep。

我希望能够对该字符串进行 grep 并显示整行,而不管该行在文本中的显示方式或位置。

【问题讨论】:

  • [.] 是一个仅包含 . 的字符类,也就是说,在我看来,您的问题并不完全是特定于时期的——您担心的是最后,不是. 是一个单字符通配符。那么,为什么标题要谈论句号呢?
  • 在开头搜索([[:space:]]|^) 并在结尾搜索([[:space:]]|$) 并没有什么不寻常的习惯。你遇到的更大的问题是你根本没有问过的问题——1.2.3 也匹配10243,因为. 是一个通配符。
  • 顺便说一句,这不应该被标记为bash -- grep 不是 bash 的一部分,它是一个外部命令,可以从任何 shell 或根本没有 shell 使用。
  • @CharlesDuffy 我不知道标题是怎么变成这样的,这不是我最初使用的标题。已编辑。我去删除 bash 标签,但它已经消失了。抱歉,不知道。
  • 明确地说,我反对的标题是 original 一个,grep 表示字符串中包含句点的变量。到我发表评论时,我已经将其修复为更清晰的内容。同样,我自己修复了 bash 标记,并且仅在评论中描述 为什么 进行了更改。

标签: unix awk grep


【解决方案1】:

假设这是您的输入文件:

cat file

5.3.236.113681.2225191122.986.3705653211.104    4
5.3.236.113681.2225191122.986.3705653211.104.3402  45
5.3.236.0.1.20549687.20.93.9.2.234266672113.4455  2
5.3.236.113681.5829104.986.3705653211.119    8
5.3.236.2.01107.50.01.24.48685.30000018053113560818700000112 172
4   5.3.236.113681.2225191122.986.3705653211.104
45  5.3.236.113681.2225191122.986.3705653211.104.3402

如果您有gnu-grep,那么您可以将此 PCRE 正则表达式与环视一起使用:

grep -P '(?<!\S)5\.3\.236\.113681\.2225191122\.986\.3705653211\.104(?!\S)' file

5.3.236.113681.2225191122.986.3705653211.104    4
4   5.3.236.113681.2225191122.986.3705653211.104

这里:

  • (?&lt;!\S): 是一个否定的后向正则表达式,用于断言我们在当前位置之前的位置没有非空格
  • (?!\S): 是一个否定的前瞻正则表达式,用于断言我们在当前位置之后的位置没有非空格

这里是POSIX投诉awk解决方案:

awk -v s='5.3.236.113681.2225191122.986.3705653211.104' '{
for (i=1; i<=NF; ++i) if ($i == s) {print; next}}' file

5.3.236.113681.2225191122.986.3705653211.104    4
4   5.3.236.113681.2225191122.986.3705653211.104

【讨论】:

  • 符合 POSIX 的 awk 解决方案现在最适合我,因为我可以使用带有该字符串的变量,例如 awk -v s='$FUID' '{for (i=1; i&lt;=NF; ++i) if ($i == s) {print; next}}' file。带有该字符串的变量可以与gnu-grep 解决方案一起使用吗?
  • awk 是最好的选择,因为我们必须转义 grep 正则表达式中的所有正则表达式元字符,例如 .(),[] 等。如果您想在 gnu-grep 中使用 shell 变量,然后转义所有这些字符以使其符合正则表达式的字符串。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-14
  • 2020-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多