128

find . -type f -print -exec cat {} \; | grep some string

Command above doesn't print the file path.

I'm using: Ubuntu, bash 4.

Alex Kulinkovich
  • 227
  • 2
  • 4
  • 15
H.Rabiee
  • 1,383
  • 2
  • 9
  • 7
  • Maybe it does not meet your expected results because of the grep filter. What about this: `find . -type f -fprint /dev/stderr -exec cat {} \; | grep some string` – wnrph Jul 02 '13 at 09:44
  • What is the goal you want to achieve? On output you are getting grepped strings from files, you want path of those files? – mirkobrankovic Jul 02 '13 at 09:58
  • Yes I want to print the path of the files that contain the string 'some string'. @artistoex suggestion prints all file paths. – H.Rabiee Jul 02 '13 at 10:01
  • You may simply want to use `ack` to grep through all files under the current directory, possibly filtering on certain file types only. – Jaap Eldering Oct 28 '15 at 20:01

5 Answers5

168

I use:

grep "some string" . -R

and it works fast.


A more complex use case:

grep -HiRE "some string|other string"

# switches used:
# -H for file printing, 
# -i for case-insensitive, 
# -R for recursive search, 
# -E for regex 

To display help on argument i:

grep --help | grep -- -i
mirekphd
  • 105
  • 4
ArcherGodson
  • 1,897
  • 1
  • 10
  • 5
  • 25
    And `-n` if you want line numbers. +1 for simplified answer. – Chad Skeeters Jul 03 '13 at 16:49
  • @ChadSkeeters exactly. Using the **find** does not give such solution. – ArcherGodson Jul 09 '13 at 12:45
  • 3
    This should be marked as the correct answer, to be honest. The currently selected one details something else entirely. –  Dec 31 '14 at 11:21
  • Use `-e "search term"` if your searching for a string that looks like an argument and if you're getting the error `invalid context length argument`, e.g. `grep -Rn . -e "-C"` – SimonH Mar 02 '23 at 08:48
131

That's because you're feeding grep a stream of text which just happens to contain filenames. Since you provided no filenames as arguments to grep, it cannot be expected to deduce what file a matched line came from. Use xargs:

find . -type f -print | xargs grep "some string"

Since you have GNU find/xargs, this is a safer way for xargs to read filenames:

find . -type f -print0 | xargs -0 grep "some string"

If you only want the filenames that have a matching line without showing the matching line:

find . -type f -print0 | xargs -0 grep -l "some string"
glenn jackman
  • 25,463
  • 6
  • 46
  • 69
  • How would I combine the above commands with search & replace? As in, grep then sed? – CMCDragonkai May 21 '15 at 14:27
  • 1
    the find|grep pipeline outputs filenames, so: `sed '...' $(find ... | xargs grep -l ...)` – glenn jackman May 21 '15 at 15:31
  • Why is the xargs necessary? Why does it not work with just grep and no xargs? What is the print0 doing? Thanks – Banoona Oct 11 '22 at 06:48
  • `find` outputs filenames. Without `xargs`, `grep` is just matching the pattern against the _filenames_ not the files' _contents_. – glenn jackman Oct 11 '22 at 13:32
  • `-print0` prints the filenames using the NUL byte as the separator instead of newline. `-0` option for xargs uses the NUL byte as well. This is used because newline is a valid character for a filename, but NUL is not valid. – glenn jackman Oct 11 '22 at 13:34
23

I often search for source code in complex folder structures and I find useful using:

cd /your/folder/
grep -rHino "your string"

With those parameters, without using find, I obtain the file full path and the line number that contains the specified string.

It is also easy to remember because it BASHes through your search like a rHino :)

I will show how this works with a quick example.

Let's display the content of a file using cat:

jeeves ~ # cat fw.stop
#!/bin/sh
echo "Stopping firewall and allowing everyone..."
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

And let's search recursively for all the files containing the string "iptables -P":

jeeves ~ # grep -rinHo "iptables -P"
fw.stop:9:iptables -P
fw.stop:10:iptables -P
fw.stop:11:iptables -P

As you can see in the output we have filename:hit row:searched string

Here's a more detailed description of the parameters used:

-r For each directory operand, read and process all files in that directory, recursively. Follow symbolic links on the command line, but skip symlinks that are encountered recursively. Note that if no file operand is given, grep searches the working directory. This is the same as the ‘--directories=recurse’ option.

-i Ignore-case.

-n Prefix each line of output with the 1-based line number within its input file. (-n is specified by POSIX.)

-H Print the file name for each match. This is the default when there is more than one file to search.

-o Print only the matched (non-empty) parts of matching lines, with each such part on a separate output line. Output lines use the same delimiters as input, and delimiters are null bytes if -z (--null-data) is also used (see Other Options).

Pitto
  • 1,856
  • 5
  • 33
  • 46
2

I prefered

| find the file |make grep ont finding file | show de full path of the file

find / -type f -exec grep 'some string' {} \; -exec echo {} \;

user515185
  • 21
  • 1
0

Silver Searcher is a very fast and handy util to search for files and content.

To solve your problem the silver searcher command would look like this...

ag 'some string' -l

-l Only print filenames that contain matches (don't print the matching lines)

qoomon
  • 230
  • 2
  • 6