Find all files having some pattern using grep in UNIX

How to find all files under a directory, having a pattern, in their name or content, in UNIX?

grep command can be used in conjunction with xargs to fetch filenames having some pattern in them.

find  /search_dir/ -iname  "*.*" -print0 | xargs -0 grep "PATTERN"

where,

search_dir is the directory where search has to begin from

PATTERN is the pattern which needs to search in the files.

Explanation,

  • find command searches the files under directory search_dir.
  • -name (without i, case sensitive) tells the find command that argument following it should be a file name pattern
  • i when added to -name (-iname) makes file name search case insensitive (Note: this doesn’t affect case sensitivity of PATTERN)
  • *.* matches any filename with any extension
  • -print0 (zero) puts a null character as separator after every search result from find command (so that grep can properly work in case file names have space or newline). Even quotes can be used to handle spaces in file names. 
  • xargs causes grep command to run on all the file names piped to it. Without xargs, the grep would try to apply PATTERN match on the file names itself and not their content.
  • PATTERN can have regular expression symbols also, to further fine tune the search e.g., grep ’^PATTERN$’ (line starting and ending with PATTERN and having nothing else).
  • Even exec could have done the same thing as xargs but latter is more efficient.
    find /path -name "file.*" -exec grep "PATTERN" {} \;

Examples,

To exclude some directory from search we can add grep -v, e.g.,

find . -iname "*.txt" -print0|grep -v /skip_dir/|xargs -0 grep "PATTERN"

Files under directory /skip_dir/ will not be searched now. A dot after find tells to start from present working directory

The output can be captured into some file (say output.txt), e.g.,

find . -iname  "file.*" -print0 | xargs -0 grep "PATTERN">output.txt

Or else, if you want to mail this content to some user on this UNIX server, use this

find . -iname "file.*" -print0|xargs -0 grep "PTRN"|mail -s "Subject" userid@server

If the file names have a space in them, then consider double quoting them before piping them to another command,

find . -iname "file.*"| sed 's/.*/"&"/'| xargs ls -l > outputfile.txt

A useful example could be to find error_log files created by PHP (parsing errors), on a web server, under various directories.

find . -iname "error_log"| sed 's/.*/"&"/'| xargs ls -l > outputfile.txt

or

find . -iname "error_log" -print0 | xargs -0 ls -l > outputfile.txt

Send a mail with this output in mail body,

find . -size +500k -iname "error_log"|sed 's/.*/"&"/'|xargs ls -l|mail -s "Error files" userid@server

This would mail you error_log files having size greater than 500KB. Though sed (special editor), to handle spaces, might not be having great importance here but it’s better to keep it for robustness of the command.

I have written a small shell script which does this job for me. Review or download it here. You are free to use it, in case you like it ;)

Using cron job you can run this at regular intervals., e.g.,

0 7 * * * root above_command

This would email every day at 0700 hrs to the userid we specify in userid@server

Note: crontab file needs to be updated with the above command. Check if you have access to cron on your server. Also make sure you type and save the above command in UNIX context and not in DOS contex.

If the file names have a space in them, then consider double quoting them before doing anything else.

Keep checking this article for more updates.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>