From the Linux shell, let's say I'm in directory /dir and I want to find, recursively in all subfolders, all the files which contain in the file name the string name_string and, inside such file(s), the string content_string. name_string might be at the beginning, center or end of the file name. How could I do that?

I was trying to use grep as:

grep -r content_string /dir/*name_string*

But I haven't been lucky so far.


3 Answers 3


For a quick solution, although maybe not as efficient as other methods,

find /dir -type f -name '*name_string*' -print0 | xargs -0 grep -l content_string
  • I was pretty far from the solution. That worked just fine, thanks! :)
    – Rocco B.
    Commented Jul 15, 2022 at 14:25

Standardly and with any shell:

find -H /dir -name '*name_string*' -type f -exec grep -lF content_string '{}' +

With the GNU implementation of grep:

grep -rlF --include='*name_string*' content_string /dir
  • -H is for the case where /dir is a symlink to a directory, so find looks for files inside that directory instead of just looking at the symlink itself. That's what GNU grep does by default with -r

  • -type f to only look into files of type regular, to the exception of any other type of file (such as directories, symlinks, fifos...). That's also what GNU grep -r does by default in recent versions.

  • -F is for Fixed string match. That would only make a difference for those strings that contain regexp operators such as . or *.

  • Quotes are needed around arguments that contain characters special in the shell syntax to make sure they're passed literally to find/grep. In all shells, that includes *. {, } have some special meaning in most shells, but for {} alone, quotes are needed in few shells, mainly rc based ones and older versions of fish. In any case, quotes don't harm.

  • -l is to only list the files with at least one match. To see the lines where the string is found in addition to the file name, you need:

    find -H /dir -name '*name_string*' -type f -exec grep -nF content_string /dev/null '{}' +
    grep -rnF --include='*name_string*' content_string /dir

I think you can use the following OR syntax:

grep -nriE '.*name_string.*|content_string' /dir

Or do what I usually do which is piping the output of first grep into another grep:

grep -nriE '.*name_string.*' /dir | grep -nri 'content_string'

  • Both of these would look inside files for name_string, not in the file's name. It is unclear whether you think the two commands are equivalent (they are not).
    – Kusalananda
    Commented Jun 9 at 7:52

You must log in to answer this question.

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