Many grep
variants implement a recursive option.
E.g., GNU grep
-R, -r, --recursive
Read all files under each directory, recursively; this is equivalent to the -d recurse option.
You can then remove find
:
grep -n -r $pattern $path | awk '{ print $1 }'
but this keeps more than the line number. awk
is printing the first column. This example
src/main/package/A.java:3:import java.util.Map;
src/main/package/A.java:5:import javax.security.auth.Subject;
src/main/package/A.java:6:import javax.security.auth.callback.CallbackHandler;
will be printed as
src/main/package/A.java:3:import
src/main/package/A.java:5:import
src/main/package/A.java:6:import
notice the :import
in each line. You might want to use sed
to filter the output.
Since a :
could be present in the file name you can use the -Z
option of grep to output a nul character (\0) after the file name.
grep -rZn $pattern $path | sed -e "s/[[:cntrl:]]\([0-9][0-9]*\).*/:\1/"
with the same example as before will produce
src/main/package/A.java:3
src/main/package/A.java:5
src/main/package/A.java:6
Using grep
Why can't you just use the -r
switch to grep
to recurse the filesystem instead of making use of find
? There are 2 additional switches I'd use too, instead of the -n
switch.
$ grep -rHn PATTERN <DIR> | cut -d":" -f1-2
Example #1
$ grep -rHn PATH ~/.bashrc | cut -d":" -f1-2
/home/saml/.bashrc:25
Details
-r
- recursively search through files + directories
-H
- prints the name of the file if it matches (less restrictive than -l
) i.e. it works with grep
's other switches
-n
- display the line number of the match
Example #2
$ grep -rHn PATH ~/.bash* | cut -d":" -f1-2
/home/saml/.bash_profile:10
/home/saml/.bash_profile:12
/home/saml/.bash_profile_askapache:99
/home/saml/.bash_profile_askapache:101
/home/saml/.bash_profile_askapache:118
/home/saml/.bash_profile_askapache:166
/home/saml/.bash_profile_askapache:218
/home/saml/.bash_profile_askapache:250
/home/saml/.bash_profile_askapache:314
/home/saml/.bash_profile_askapache:2317
/home/saml/.bash_profile_askapache:2323
/home/saml/.bashrc:25
Using find
$ find . -exec sh -c 'grep -Hn PATTERN "$@" | cut -d":" -f1-2' {} +
Example
$ find ~/.bash* -exec sh -c 'grep -Hn PATH "$@" | cut -d":" -f1-2' {} +
/home/saml/.bash_profile:10
/home/saml/.bash_profile:12
/home/saml/.bash_profile_askapache:99
/home/saml/.bash_profile_askapache:101
/home/saml/.bash_profile_askapache:118
/home/saml/.bash_profile_askapache:166
/home/saml/.bash_profile_askapache:218
/home/saml/.bash_profile_askapache:250
/home/saml/.bash_profile_askapache:314
/home/saml/.bash_profile_askapache:2317
/home/saml/.bash_profile_askapache:2323
/home/saml/.bashrc:25
If you truly want to use find
you can do something like this to exec grep
upon finding the files using find
.
Best Answer
The command line switch
-H
forcesgrep
to print the file name, even with just one file.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).