68

When I want to perform a recursive grep search in the current directory, I usually do:

grep -ir "string" .

But that command searches inside all kinds of files, including binary files (pictures, audio, video, etc...) which results in a very slow search process.

If I do this, for example, it doesn't work:

grep -ir "string" *.php

It doesn't work because there are no PHP files inside the current directory, but inside some of the subdirectories in the current directory, and the subdirectories' names don't end with ".php" so grep doesn't look inside them.

So, how can I do a recursive search from the current directory but also specifying filename wildcards? (i.e: only search in files which end in a specific extension)

3 Answers 3

97

Use grep's --include option:

grep -ir "string" --include="*.php" .
4
  • 1
    Ok, it seems my version of grep was old, because it didn't have that option (no wonder why I couldn't figure out how to do this!). I got the message: "grep: unrecognized option `--include=*.php'". But I just upgraded to a newer one and now it works. Thank you!
    – OMA
    Commented May 23, 2014 at 9:03
  • I had to replace the period at the end and use: grep -ir "string" --include="*.php" *
    – Stuart
    Commented Jul 21, 2015 at 17:41
  • I thought period was just the end of the line! I did not use or need.
    – boardtc
    Commented Nov 5, 2018 at 14:59
  • Is there a way to make grep's --include option case-insensitive? So that the command would output both *.php and *.PHP files. -i seem to apply only to what is searched inside of the targeted filenames, and not to the filenames themselves.
    – John Smith
    Commented Nov 3, 2021 at 17:13
17

If you have a version of grep that lacks the --include option, you can use the following. These were both tested on a directory structure like this:

$ tree
.
├── a
├── b
│   └── foo2.php
├── c
│   └── d
│       └── e
│           └── f
│               └── g
│                   └── h
│                       └── foo.php
├── foo1.php
└── foo.php

Where all the .php files contain the string string.

  1. Use find

    $ find . -name '*php' -exec grep -H string {} +
    ./b/foo2.php:string
    ./foo1.php:string
    ./c/d/e/f/g/h/foo.php:string
    

    Explanation

    This will find all .php files and then run grep -H string on each of them. With find's -exec option, {} is replaced by each of the files found. The -H tells grep to print the file name as well as the matched line.

  2. Assuming you have a new enough version of bash, use globstar :

    $ shopt -s globstar
    $ grep -H string  **/*php
    b/foo2.php:string
    c/d/e/f/g/h/foo.php:string
    foo1.php:string
    

    Explanation

    As explained in the bash manual:

    globstar

    If set, the pattern ‘**’ used in a filename expansion context will match all files and zero or more directories and subdirectories. If the pattern is followed by a ‘/’, only directories and subdirectories match.

    So, by running shopt -s globstar you are activating the feature and Bash's globstar option which makes **/*php expand to all .php files in the current directory (** matches 0 or more directories, so **/*php matches ./foo.php as well) which are then grepped for string.

-2

Use */*.php

This makes grep search one level of subdirectory

3
  • Something went wrong as asterisks and dots disappeared. Commented Apr 5, 2016 at 9:13
  • You can use backticks to format code and avoid ambiguity about the use of asterisks for emphasis in markdown formatting. P.S. note the question asks about "recursive search" in the final paragraph (not my downvote though). Commented Apr 5, 2016 at 9:20
  • Not a correct answer, because it's only good for one level deep directory structures, as you mention, but still good to know nonetheless ;). My upvote for that.
    – OMA
    Commented Jan 5, 2017 at 4:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .