title: Whole-word matching on a body of text, given a list of words
body: <p><strong>Note:</strong></p>
  
  <p>Before I get down to business, I'd like to point out some other SO posts that didn't quite answer my question and are not duplicates of this one:</p>
  
  <ul>
  <li><a href="https://stackoverflow.com/questions/17863301/how-to-grep-with-a-list-of-words">How to grep with a list of words</a></li>
  <li><a href="https://stackoverflow.com/questions/4709912/how-to-grep-the-exact-match">How to make grep only match if the entire line matches?</a></li>
  <li><a href="https://stackoverflow.com/questions/2879085/how-to-grep-for-the-whole-word">how to grep for the whole word</a></li>
  <li><a href="https://stackoverflow.com/questions/17616012/grep-extract-only-whole-word">Grep extract only whole word</a></li>
  </ul>
  
  <p><strong>Background:</strong></p>
  
  <p>I have a list of words in a file called <code>words.txt</code> (one word per line). I would like to find all lines from a different, much larger file called <code>file.txt</code> that contain any of the words from <code>words.txt</code>. However, I only want <em>whole-word</em> matches. This means that a match should be made when a line from <code>file.txt</code> contains at least one instance where a word from <code>words.txt</code> is found "all by itself" (I know this is vague, so allow me to explain).</p>
  
  <p>In other words, a match should be made when:</p>
  
  <ol>
  <li>The word is all by itself on a line</li>
  <li>The word is surrounded by non-alphanumeric/non-hyphen characters</li>
  <li>The word is at the beginning of a line and followed by a non-alphanumeric/non-hyphen character</li>
  <li>The word is at the end of a line and preceded by a non-alphanumeric/non-hyphen character</li>
  </ol>
  
  <p>For example, if one of the words in <code>words.txt</code> is <code>cat</code>, I would like it to behave as follows:</p>
  
  <pre><code>cat              #=&gt; match
  cat cat cat      #=&gt; match
  the cat is gray  #=&gt; match
  mouse,cat,dog    #=&gt; match
  caterpillar cat  #=&gt; match
  caterpillar      #=&gt; no match
  concatenate      #=&gt; no match
  bobcat           #=&gt; no match
  catcat           #=&gt; no match
  cat100           #=&gt; no match
  cat-in-law       #=&gt; no match
  </code></pre>
  
  <p><strong>Previous research:</strong></p>
  
  <p>There's a <code>grep</code> command that <em>almost</em> suits my needs. It is as follows:</p>
  
  <p><code>grep -wf words.txt file.txt</code></p>
  
  <p>where the options are:</p>
  
  <pre><code>-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.
  </code></pre>
  
  <p>The big problem I'm having with this is that it treats a hyphen (i.e. <code>-</code>) as a "non-word constituent character". Therefore (based on the example above) doing a <em>whole-word</em> search for <code>cat</code> will return <code>cat-in-law</code>, which is not what I want.</p>
  
  <p>I realize that the <code>-w</code> option probably achieves the desired effect for many people. However, in my particular case, if a word (e.g. <code>cat</code>) is followed/preceded by a hyphen, then I need to treat it as if it's part of a larger word (e.g. <code>cat-in-law</code>) and not an instance of the word by itself.</p>
  
  <p>Additionally, I know I could alter <code>words.txt</code> to contain regular expressions instead of fixed strings and then use:</p>
  
  <p><code>grep -Ef words.txt file.txt</code></p>
  
  <p>where</p>
  
  <pre><code>-E, --extended-regexp
                Interpret PATTERN as an extended regular expression
  </code></pre>
  
  <p>However, I would like to avoid altering <code>words.txt</code> and keep it free of regex patterns.</p>
  
  <p><strong>Question:</strong></p>
  
  <p>Is there a simple bash command that will allow me to give it a list of words and perform <em>whole-word</em> matching on a body of text?</p>