使用grep匹配整个单词的问题

时间:2019-03-26 22:36:24

标签: linux string bash grep string-matching

我正在尝试在新行分隔的字符串列表中匹配整个字符串。这是我的示例:

[hemanth.a@gateway ~]$ echo $snapshottableDirs
/user/hemanth.a/dummy1 /user/hemanth.a/dummy3
[hemanth.a@gateway ~]$ echo $snapshottableDirs | tr -s ' ' '\n'
/user/hemanth.a/dummy1
/user/hemanth.a/dummy3
[hemanth.a@gateway ~]$ echo $snapshottableDirs | tr -s ' ' '\n' | grep -w '/user/hemanth.a'
/user/hemanth.a/dummy1
/user/hemanth.a/dummy3

我的目标是仅在字符串列表中字符串/user/hemanth.a作为一个整体单词(在新行中)存在时,才找到匹配项。但是,上面的命令还会返回包含/user/hemanth.a的字符串。

这是一个示例方案。无法保证我要匹配的所有字符串都将采用/user/xxxxxx.x的形式。理想情况下,如果列表中的整个单词都以换行形式存在,则我希望匹配确切的字符串。

任何帮助将不胜感激。谢谢。

2 个答案:

答案 0 :(得分:3)

更新:这里使用fgrep -x '/user/hemanth.a'可能是一个更好的解决方案,因为它避免了必须转义$这样的字符以防止grep解释为元字符。 fgrep执行文字字符串匹配,而不是正则表达式匹配,并且-x选项告诉它仅匹配整行。

示例:

> cat testfile.txt
foo
foobar
barfoo
barfoobaz

> fgrep foo testfile.txt
foo
foobar
barfoo
barfoobaz

> fgrep -x foo testfile.txt
foo

原始答案

尝试在$表达式的末尾添加grep正则表达式元字符,如下所示:

echo $snapshottableDirs | tr -s ' ' '\n' | grep -w '/user/hemanth.a$'. 

$元字符与行尾匹配。

在进行此操作时,您可能还想使用^元字符,该字符与行的开头相匹配,因此grep '/user/hemanth.a$'不会偶然也与{{1 }}。

所以你会得到这个:

/user/foo/user/hemanth.a

编辑:您可能实际上并不希望在这里使用echo $snapshottableDirs | tr -s ' ' '\n' | grep '^/user/hemanth\.a$'. ,所以我将其从答案中删除了。

编辑2 :@U。 Windl提出了一个观点。正则表达式中的-w字符是与 any 字符匹配的元字符,因此.可能最终与您不期望的内容匹配,例如grep /user/hemanth.a等等。或者更可能的是,它也将与行/user/hemanthxa相匹配。要解决此问题,您需要转义/user/hemanth/a字符。我已经更新了上面的.行以反映这一点。

更新:针对您在注释中有关如何转义字符串以便可以在grep正则表达式中使用它的评论...

是的,您可以转义字符串,以便可以在正则表达式中使用它。我将解释如何执行此操作,但是首先我应该说,在许多奇怪的边缘情况下,尝试转义用于正则表达式的字符串可能会变得非常复杂。例如,与grep一起使用的转义字符串不一定与grepsedawk,bash的perl运算符甚至{{ 1}}。

最重要的是,如果您从单引号更改为双引号,则可能必须添加另一级转义,以便bash可以正确扩展您的字符串。

例如,如果您想使用=~搜索文字字符串grep -e,则必须转义'foo [bar]* baz$',{{1 }}和grep个字符,得出正则表达式:

[

但是,如果由于某种原因您决定将该表达式作为双引号字符串传递给*,则必须转义转义符。否则,bash会将其中一些解释为转义符。您可以通过以下方式查看此信息:

$

您可以看到bash将'foo \[bar]\* baz\$' 解释为代表字符grep的转义序列,从而吞噬了echo "foo \[bar]\* baz\$" foo \[bar]\* baz$ 字符。这是因为通常在双引号字符串\$中是一个特殊字符,它开始参数扩展。但由于$\在双引号字符串中并不特殊,因此它单独保留了$\[,因此它将反斜杠解释为文字\*字符。为了使该表达式能够在双引号字符串中用作[的参数,则必须转义最后一个反斜杠:

*

但是请注意,\不能与grep一起使用,因为# This command prints nothing, because bash expands `\$` to just `$`, # which grep then interprets as an end-of-line anchor. > echo 'foo [bar]* baz$' | grep "foo \[bar]\* baz\$" # Escaping the last backslash causes bash to expand `\\$` to `\$`, # which grep then interprets as matching a literal $ character > echo 'foo [bar]* baz$' | grep "foo \[bar]\* baz\\$" foo [bar]* baz$ 使用不同的正则表达式语法,转义"foo \[bar]\* baz \\$"会导致它{要成为一个元字符,而在sed中,您必须对其进行转义以防止将其解释为元字符。

同样,是的,您可以转义文字字符串以用作sed正则表达式。但是,如果您需要匹配包含需要转义的字符的文字字符串,那么事实证明,还有一种更好的方法:[

grep命令实际上只是grep的简写,其中fgrep告诉fgrep匹配“固定字符串”而不是正则表达式。例如:

grep -F

之所以起作用,是因为-F不了解或不关心正则表达式。它只是在寻找确切的文字字符串grep。但是,由于> echo '[(*\^]$' | fgrep '[(*\^]$' [(*\^]$ 将在子字符串上匹配,因此这种情况使您回到第一个平方。

fgrep

很高兴,有一个解决方法,事实证明,考虑到您的特定需求,这可能是比我最初的回答更好的方法。 '[(*\^]$'的{​​{1}}选项告诉它仅匹配整行。请注意,fgrep并非特定于> echo '/users/hemanth/dummy' | fgrep '/users/hemanth' /users/hemanth/dummy (因为-x实际上只是fgrep)。例如:

-x

这等效于转义fgrep的正则表达式,几乎可以肯定比我以前的将正则表达式包含在fgrepgrep -F中的答案更好。

现在,如所承诺的那样,以防万一,如果您想走这条路,这是您转义固定字符串以用作> echo '/users/hemanth/dummy' | fgrep -x '/users/hemanth' # prints nothing 正则表达式的方法:

grep

同样,出于上述原因,我不建议您使用这种方法,尤其是当^存在时。

答案 1 :(得分:1)

filePath.replacingOccurrences(of: "file://", with: "") 中阅读“锚定”:

man grep

还请注意, Anchoring The caret ^ and the dollar sign $ are meta-characters that respectively match the empty string at the beginning and end of a line. 与任何字符都匹配(来自所述手册页):

.