4

How I can make the grep command locate certain words in the files specified by the routes found by the locate command?

locate my.cnf | grep user   

(I want that grep command search the word "user" on the files found for locate command)

Jhonathan
  • 3,605

3 Answers3

9

If your search results are sure to return paths with no spaces, you could use xargs like this:

locate my.cnf | xargs grep user

However you should get in the habit of protecting yourself to handle the case where a path or filename might contain a space by telling xargs to use null as a separator and telling locate (or whatever program you are using to return strings) to also send that as the separator like this:

locate -0 my.cnf | xargs -0 grep user

This would work even if your path included blanks like /name with space/my.cnf.

Caleb
  • 70,105
Jhonathan
  • 3,605
  • Slightly more idiomatic than mine. – nikitautiu Sep 10 '12 at 15:55
  • You might want locate my.cnf | xargs grep -H user so that the output lines report which file(s) the match was found in. – StarNamer Sep 10 '12 at 23:20
  • i'd use locate -0 my.cnf | xargs -0 -r grep user in case any filenames had spaces etc in them. Note that not all versions of locate support the -0 or --null option for null-terminated output. mlocate does. IIRC, GNU locate does too. – cas Sep 11 '12 at 00:50
  • @vitiv: It's not slightly more idomatic, yours just doesn't work. Try it. Even when you fix it, then you have to add even more fixes to handle paths with spaces. By the time it actually works, yours will be the more idomatic, although in a more complex setup it could also be the better choice. – Caleb Sep 11 '12 at 22:47
1

If I understand correctly, you could do something like this:

#!/bin/sh
typeset what1=$1
typeset what2=$2
[ "$#" -eq 2 ] || { echo "Two arguments expected"; exit 1; }
locate ${what1} | while read file; do
    grep ${what2} ${file} /dev/null
    done

This searches the files matching the locate argument (what1) for a string that matches what2. The dev/null argument forces grep to report the file name of a match.

JRFerguson
  • 14,740
  • Interesting hack by adding /dev/null, although you can also echo the file name yourself. – Caleb Sep 11 '12 at 22:50
  • @Caleb : Yes I could have added an echo ${file} but I dislike having to spawn yet another process just for that purpose. – JRFerguson Sep 11 '12 at 23:03
  • There is typically a shell builtin for echo so it does not spawn a process anyway. – Caleb Sep 11 '12 at 23:26
  • @Caleb : Ah, yes, I forgot that. Thanks! – JRFerguson Sep 11 '12 at 23:27
  • If you were worried about that, doesn't adding /dev/null force grep to open a file pointer to it for ever iteration over the loop? That would cost more than an echo I'd think. – Caleb Sep 11 '12 at 23:30
  • 1
    Actually the real problem is the gymnastics of getting it to do the echo before the match only if there is a match. It can be done but it's kind of ugly. Usually I don't want the matches at all however so it's grep -q "#what2" && [other action]. As I said, that is an interesting hack however and I'll remember it, may come in handy although I tend to dislike things that their function isn't readily apparent to somebody reading the code. – Caleb Sep 11 '12 at 23:31
1

One-liner:

for file in $(locate my.cnf) ; do grep -r user "$file" ; done

If you want to search pattern in files under the directory name you got from locate then -r will take care of it otherwise remove -r.

Caleb
  • 70,105