1

I want to locate all text-files within a directory tree containing two words, word1 and word2 (for example). I cannot just grep for word1 word2, because this will only find occurrences where the two words appear consecutively. I want to find all files that contain both these two words, but not necessarily consecutive.

Ideally, the search should print file names as well as the context where the terms were found inside the files. This would be very helpful. A GUI wouldn't hurt.

How can I do it?

a06e
  • 1,727
  • https://unix.stackexchange.com/questions/293058/find-files-that-contain-multiple-keywords-anywhere-in-the-file?rq=1 has some ideas – Jeff Schaller Apr 23 '18 at 18:24
  • @JeffSchaller Regretably that doesn't show the context of the words found. – a06e Apr 23 '18 at 18:32
  • Would grep -E -C 3 'word1|word2' $(list of files that contain both strings) show the sort of context you want? – Mark Plotnick Apr 23 '18 at 18:37
  • @MarkPlotnick I think so. That's clever. Now how do you connect that the rest of the command? – a06e Apr 23 '18 at 18:41
  • @MarkPlotnick Also note that I have a list of words that can be bash arguments, if I want to automatize this somehow. – a06e Apr 23 '18 at 18:45

4 Answers4

1

I would use find's feature where each test has to pass in order for the file to be considered a match. Chain two grep commands together to match the criteria:

find . -type f -exec grep -q word_one {} \; -exec grep -l word_two {} \;

You can adjust the flags to grep as needed, including quoting the words if they have any shell-special or regex-special characters (or using grep -F).

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
1

How to search files where two different words exist? has many good solutions to your basic problem.  To handle your additional requirement to show context, we need only take one of those answers (e.g., Stéphane’s) and add a little bit to it:

find . -type f -exec grep -q word1 {} ';' -exec grep -q word2 {} ';'  \
                                            -exec grep -A3 -B3 -E -H 'word1|word2' {} +

The find . -type f -exec grep -q word1 {} ';' -exec grep -q word2 {} ';' part is just Stéphane’s second answer (the portable but simple one) with the -l option to the second grep (to list filenames) replaced with -q (to search and quietly exit with status).  We then tack on a final grep to display results.  -A3 and -B3 show three lines after and three lines before every match; adjust these to your taste. The -E is necessary to get the extended regular expression word1|word2 to work without a \; the -H forces grep to print the filename even if there’s only one file.

  • Thanks. "-H forces grep to print the filename even if there’s only one file" Do you mean only one matching file or only one file to search? – Tim Jun 02 '18 at 01:58
0

You would do with grep:

grep -Elrz "word2(.|\n)*word1|word1(.|\n)*word2" .

If you need to have matched content in output, then remove the l option above.

αғsнιη
  • 41,407
-1

My first thought would be to search for files that contain word1 first and then search among them for files that contain word2. It would be:

grep -l word1 -r . | xargs grep -l word2

Example:

$ cat FILE
word1
$ cat FILE1
word2
$ cat FILE2
word1
word2
$ grep -l word1 -r . | xargs grep -l word2
FILE2

Tested with both GNU and FreeBSD userland.

  • Is there a way to print the context where the terms are found within the files? – a06e Apr 23 '18 at 18:40
  • @becko: as Mark Plotnick said in the comment above: grep -E -C 3 'word1|word2' $(grep -lr word1 | xargs grep -l word2) – Arkadiusz Drabczyk Apr 23 '18 at 18:44
  • Is there a way to create bash script doing this? I am trying to do it, but I do not know how to convert a list of arguments to the script into $arg1|$arg2 ..., where the number of arguments can be arbitary – a06e Apr 23 '18 at 18:45