I am having trouble with the Linux find and grep commands. Basically I need to CD to a directory, recursive find all example.txt files modified after a particular date and then execute grep on those files. The command below is working (somewhat) but it gives multiple results of same file and I am not sure how stable it is.

find ./ -name "example.xml" -newermt "2018-01-01" -exec grep -r "videoplayer.1" /. \;
  • 1
    Your missing {} at the end of grep! Perhaps this would help: find ./ -name "example.xml" -newermt "2018-01-01" -exec grep -r "videoplayer.1" {} \; Jan 12 '18 at 17:33
find ./ -name "example.xml" -newermt "2018-01-01" -exec grep -r "videoplayer.1" /. \;

This would find, starting at the current directory ./, files with the -name example.xml that are newer (in modification time) than 2018-01-01 and for each of them, execute the command grep -r "videoplayer.1" /..

But we see that the grep command does not take the file name found by find into account, but instead the command is always constant. Furthermore, it starts a recursive (-r) search from the root of the filesystem (/.). Now, that may be a typo (./ vs. /.), but the meaning changes completely.

Even with grep -r ... ./, the search would be recursive starting from the current directory, and with -exec, that's the directory where find was started.

With find -exec, you need to use the {} placeholder to tell find where to insert the filename currently being processed. So

find ./ -name "example.xml" -newermt "2018-01-01" -exec grep  "videoplayer.1" {} \;

To run grep videoplayer.1 filename on all files named example.xml that are newer than January 1st 2018.

Actually, you could do replace the \; that terminates the -exec command with a + to have find pass multiple files to one invocation of grep. That would make the whole job faster, since less processes need to be started:

find ./ -name "example.xml" -newermt "2018-01-01" -exec grep  "videoplayer.1" {} \+

Also, if you want to make sure grep lists the name of the file it's processing, you can use the -H flag (in at least GNU and BSD grep):

  -H, --with-filename       

Print the file name for each match. This is the default when there is more than one file to search.

(An alternative to -H would be to add something like /dev/null to the list of files given to grep)

  • Thanks for the detailed explanation, this is the final version of the command which I am planning to use - find ./ -name "example.xml" -newermt "2018-01-01" -exec grep "videoplayer.1" {} ./ \; Basically the same as the suggested above but with extra "./" so I can see the path and file. Jan 13 '18 at 12:28
  • @VitaliyTerziev, yeah, GNU and BSD grep have the -H option, which tells it to print the file name in any case. It's what happens by default if multiple files are listed. Also, I forgot to mention find -exec ... {} +, which would be better. Edited notes on both.
    – ilkkachu
    Jan 13 '18 at 12:36
  • Thanks a lot for the details and examples, I have final version of the command now. :) find ./ -name "example.xml" -newermt "2018-01-01" -exec grep -H "videoplayer.1" {} \+ Jan 13 '18 at 13:00

I would think the correct form of that command is:

find ./ -name "example.xml" -newermt "2018-01-01" -exec grep -r "videoplayer.1" {} \;

Missing the {} part in the find command. Your find results aren't being passed to grep.

  • Thanks, George. I think your solution is working but id does not show the path of the file, I've modified it a bit - find ./ -name "example.xml" -newermt "2017-01-08" -exec grep "videoplayer.1" {} ./ \; Do you think that it is reliable? Jan 12 '18 at 17:41
  • Remove the \; and use + and see if it helps Jan 12 '18 at 17:45
  • 1
    With \; you are passing only a single file at a time to grep, so it won't print the filename by default - you will need to add the -H option if you want it to add the name. Or add a -print to the find command. Jan 12 '18 at 18:48
  • Would + not be ok too, and the -print prints all file names Jan 12 '18 at 19:28
  • 1
    @VitaliyTerziev as you wish my lord, :)! Jan 13 '18 at 13:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.