注意:
在开始创业之前,我想指出一些其他SO帖子并没有完全回答我的问题而且与这个问题不重复:
背景
我在一个名为words.txt
的文件中有一个单词列表(每行一个单词)。我想从名为file.txt
的另一个更大的文件中找到所有行,其中包含来自words.txt
的任何单词。但是,我只想要全字匹配。这意味着当来自file.txt
的一行包含至少一个找到words.txt
的单词的实例&#34时,应该进行匹配;所有这些都是单独的" (我知道这很模糊,所以请允许我解释一下)。
换句话说,应该在以下情况下进行匹配:
例如,如果words.txt
中的某个字词为cat
,我希望其行为如下:
cat #=> match
cat cat cat #=> match
the cat is gray #=> match
mouse,cat,dog #=> match
caterpillar cat #=> match
caterpillar #=> no match
concatenate #=> no match
bobcat #=> no match
catcat #=> no match
cat100 #=> no match
cat-in-law #=> no match
之前的研究:
有grep
命令几乎符合我的需要。它如下:
grep -wf words.txt file.txt
选项包括:
-w, --word-regexp
Select only those lines containing matches that form whole words.
The test is that the matching substring must either be at the beginning
of the line, or preceded by a non-word constituent character.
Similarly, it must be either at the end of the line or followed by a
non-word constituent character. Word-constituent characters are
letters, digits, and the underscore.
-f FILE, --file=FILE
Obtain patterns from FILE, one per line. The empty file contains
zero patterns, and therefore matches nothing.
我遇到的一个大问题是,它将连字符(即-
)视为"非单词构成字符"。因此(基于上面的示例)对cat
执行全字搜索将返回cat-in-law
,这不是我想要的。
我意识到-w
选项可能会为许多人带来预期的效果。但是,在我的特定情况下,如果一个单词(例如cat
)后跟/前面有一个连字符,那么我需要将其视为一个较大单词的一部分(例如{{1} })而不是单词本身的实例。
此外,我知道我可以改变cat-in-law
包含正则表达式而不是固定字符串然后使用:
words.txt
,其中
grep -Ef words.txt file.txt
但是,我希望避免更改-E, --extended-regexp
Interpret PATTERN as an extended regular expression
并使其免于正则表达式模式。
问题:
是否有一个简单的bash命令可以让我给它一个单词列表并在文本正文上执行全字匹配?
答案 0 :(得分:4)
我终于想出了一个解决方案:
grep -Ef <(awk '{print "([^a-zA-Z0-9-]|^)"$0"([^a-zA-Z0-9-]|$)"}' words.txt) file.txt
<强>解释强>
words.txt
是我的单词列表(每行一个)。file.txt
是我要搜索的文字正文。awk
命令将动态预处理words.txt
,将每个单词包装在一个特殊的正则表达式中,以定义其正式的开始和结束(根据我上面的问题中发布的规范)。 awk
命令被<(
和)
包围,因此其输出将用作-f
选项的输入。-E
选项,因为我现在正在输入正则表达式列表而不是words.txt
中的固定字符串。这里的好处是words.txt
可以保持人类可读性,并且不必包含一堆正则表达式模式。