gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:54:45 24 4
gpt4 key购买 nike

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

[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格式的。理想情况下,我想匹配确切的字符串,如果它存在于一个新的行中,作为列表中的一个完整的单词。
任何帮助都将不胜感激。谢谢您。

最佳答案

更新:在这里使用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

原始答案:
尝试将 $regex元字符添加到 grep表达式的末尾,如下所示:
echo $snapshottableDirs | tr -s ' ' '\n' | grep -w '/user/hemanth.a$'. 

$元字符与行尾匹配。
在使用时,您可能还需要使用与行开头匹配的 ^元字符,这样 grep '/user/hemanth.a$'就不会意外地与类似于 /user/foo/user/hemanth.a的内容匹配。
所以你会得到这个:
echo $snapshottableDirs | tr -s ' ' '\n' | grep '^/user/hemanth\.a$'. 

编辑:你可能不希望这里有 -w,所以我已经把它从我的答案中删除了。
编辑二:@u.windl提出了一个很好的观点。正则表达式中的 .字符是与任何字符匹配的元字符,因此 grep /user/hemanth.a最终可能会匹配您不期望的内容,例如 /user/hemanthxa等,或者更可能的是,它还会匹配行 /user/hemanth/a。要解决这个问题,您需要转义 .字符。我已经更新了上面的 grep行来反映这一点。
更新:针对您在注释中提出的关于如何转义字符串以便在 grep正则表达式中使用它的问题…
是的,可以对字符串进行转义,以便它能够在正则表达式中使用。我将解释如何这样做,但首先我应该说,尝试转义字符串以在正则表达式中使用可能会变得非常复杂,有很多奇怪的边缘情况。例如,与 grep一起工作的转义字符串不一定与 sedawkperl、bash的 =~运算符一起工作,甚至不一定与 grep -e一起工作。
除此之外,如果将单引号改为双引号,则可能需要添加另一级别的转义,以便bash能够正确扩展字符串。
例如,如果要使用 'foo [bar]* baz$'搜索文本字符串,则必须转义 grep[*字符,从而生成正则表达式:
'foo \[bar]\* baz\$'

但是,如果出于某种原因,您决定将该表达式作为双引号字符串传递给 $,则必须转义。否则,bash会将其中一些解释为逃避。如果这样做,您可以看到:
echo "foo \[bar]\* baz\$"
foo \[bar]\* baz$

您可以看到bash将 grep解释为一个表示字符 \$的转义序列,从而吞入了 $字符。这是因为在双引号字符串中,通常 \是一个特殊字符,开始参数扩展。但它只留下了 $\[,因为 \*[在双引号字符串中不特殊,所以它将反斜杠解释为literal *字符。若要使此表达式在双引号字符串中用作 \的参数,则必须转义最后一个反斜杠:
# 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$

但是请注意, grep不能与 "foo \[bar]\* baz \\$"一起使用,因为 sed使用不同的regex语法,在这种语法中,转义a sed会导致它成为元字符,而在 [中,您必须转义它以防止它被解释为元字符。
同样,是的,您可以转义一个文本字符串作为正则表达式使用。但如果需要匹配包含需要转义的字符的文本字符串,则有更好的方法: grep
grep命令实际上只是 fgrep的简写,其中 fgrep告诉 grep -F匹配“固定字符串”而不是正则表达式。例如:
> echo '[(*\^]$' | fgrep '[(*\^]$'
[(*\^]$

这是因为 -F不知道或不关心正则表达式。它只是在寻找确切的文本字符串 grep。但是,这种情况会使您回到原点,因为 fgrep将在子字符串上匹配:
> echo '/users/hemanth/dummy' | fgrep '/users/hemanth'
/users/hemanth/dummy

谢天谢地,有办法解决这个问题,考虑到你的具体需求,这可能是比我最初的答案更好的方法。 '[(*\^]$'选项告诉它只匹配整行。请注意, fgrep并不特定于 -x(因为 fgrep实际上只是 -x)。例如:
> echo '/users/hemanth/dummy' | fgrep -x '/users/hemanth' # prints nothing

这相当于您通过转义 fgrepregex得到的结果,而且几乎可以肯定,这是一个比我之前将regex括在 fgrepgrep -F中更好的答案。
现在,正如所承诺的,为了防止您想走这条路,下面是如何转义一个固定字符串以用作 grepregex:
# Suppose we want to match the literal string '^foo.\ [bar]* baz$'
# It contains lots of stuff that grep would normally interpret as
# regular expression meta-characters. We need to escape those characters
# so grep will interpret them as literals.
> str='^foo.\ [bar]* baz$'
> echo "$str"
^foo.\ [bar]* baz$

> regex=$(sed -E 's,[.*^$\\[],\\&' <<< "$str")
> echo "$regex"
\^foo\.\\ \[bar]\* baz\$

> echo "$str" | grep "$regex"
^foo.\ [bar]* baz$
# Success

再次,由于上面提到的原因,我不推荐这种方法,尤其是当 ^存在时。

关于linux - 使用grep匹配整个单词的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55367162/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com