user1323995
user1323995

Reputation: 1366

How to search with grep in files specified in a text file?

I want to search with grep for a pattern in a number of files which I specified in a previous step and which are now stored in a text file.

Lets say, in the first step, I used

grep -l 'pattern1' *.csv >> ~/filenames.txt 

to list the filenames of all the csv files which contained pattern1 and save these filenames into filenames.txt

Now I would like to search all of the above files for a second pattern, pattern2. I'm looking for a command like

grep -?? 'pattern2' ~/filenames.txt

where -?? tells grep to look for filenames in filenames.txt I know that

grep -f patternfile.txt *.csv

Would search all csv files for the patterns defined in patternfile.txt. Is there an analog command for searching all files specified in a file full of filenames?

I'm also happy to hear about alternative solution to my overall problem, e.g. somehow combining step 1 and 2 without the interim filenames.txt but it would also be interesting to know about the analog grep command, if it exists.

To be clear, I am not just looking for files which contain pattern1 and pattern2. I'm interested in all occurrences for pattern2 (and then actually count them) in files in which pattern1 appears at least once.

Upvotes: 1

Views: 2159

Answers (3)

mklement0
mklement0

Reputation: 440162

To:

  • avoid the need for an intermediate file,
  • and robustly handle filenames with embedded spaces or globbing pattern characters,

try the following (assumes that you're either on Linux or BSD/OSX):

grep -l --null 'pattern1' *.csv | xargs -0 grep 'pattern2'
  • -l tells grep to print only the input filename in case of a match
  • --null separates the filenames with NULs
  • xargs -0 parses the NUL-separated filenames into individual arguments and passes them to the 2nd grep command.

On Linux (with GNU utilities), you can simplify the command somewhat, assuming you're not worried about filenames with embedded newlines (very rare):

grep -l 'pattern1' *.csv | xargs -d '\n' grep 'pattern2'
  • -d '\n' makes xargs consider each input line as a whole an individual argument.

Upvotes: 2

anubhava
anubhava

Reputation: 786031

You can use xargs for this:

xargs -I {} grep -H 'pattern' {} < ~/filenames.txt

grep will run against filename on each line from ~/filenames file.

This will also work with spaces in filenames.

Upvotes: 3

JJoao
JJoao

Reputation: 5357

or...

ack --files-from=filenames.txt 'pattern'

Upvotes: 1

Related Questions