60

When using find, how do I return the file name and the line number when searching for a string? I manage to return the file name in one command and the line numbers with another one, but I can't seem to combine them.

File names: find . -type f -exec grep -l 'string to search' {} \;

Line numbers: find . -type f -exec grep -n 'string to search' {} \;

3 Answers 3

75

The command line switch -H forces grep to print the file name, even with just one file.

% grep -n 7 test.in
7:7
% grep -Hn 7 test.in
test.in:7:7

   -H, --with-filename
          Print the filename for each match.

Note that as Kojiro says in a comment, this is not part of the POSIX standard; it is in both GNU and BSD grep, but it's possible some systems don't have it (e.g. Solaris).

1
  • 4
    This answer could be improved by pointing out that the -H flag to grep is a nonstandard GNU extension and posing an alternative approach for non-GNU systems.
    – kojiro
    Oct 28, 2012 at 3:43
26

Unless you use the non-standard -H or -r/-R options, grep only outputs the file name if passed more than one file name, so you can do:

find . -type f -exec grep -n 'string to search' /dev/null {} +

With the {} + syntax, find will pass as many files as needed to grep, while with {} ';', it runs one grep per file which is inefficient.

We still add /dev/null (which is guaranteed to exist and be empty) which makes sure grep gets at least two files, for the cases where there's only one regular file in the current directory or below or the list of files has been split by find in such a way that the last run has only one file.

As a side note, with -exec grep regex {} +, find's exit status will be non-zero if any of the grep invocations terminated with a non-zero exit status. It will also be non-zero if find fails to traverse/read some directories or get file metadata. If find returns with a zero exit status, that means find could traverse all directories and all grep invocation succeeded (found at least one file with at least one match), but if it returns non-zero, that doesn't necessarily mean no match was found.

With -exec grep regex {} ';', grep's exit status is only used to determine whether the -exec predicate (which could be used as a condition) succeeds, it's not reflected in find's exit status. So find's exit status will only be about whether it could find all the files.

3
2

If your grep supports the recursive -r flag, this solves your request:

grep -rn "String to search " * 
2
  • 1
    That's true, but I don't see what this adds to the existing answers.
    – Wildcard
    Jul 18, 2017 at 0:48
  • And if there’s only one (non-dot) file in the current directory, this doesn’t display the file’s name. Oct 19, 2017 at 23:56

You must log in to answer this question.

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