views:

697

answers:

3

To see all the php files that contain "abc" I can use this simple script:

find . -name "*php" -exec grep -l abc {} \;

I can omit the -l and i get extracted some part of the content instead of the filenames as results:

find . -name "*php" -exec grep abc {} \;

What I would like now is a version that does both at the same time, but on the same line.

Expected output:

path1/filename1: lorem abc ipsum
path2/filename2: ipsum abc lorem
path3/filename3: non abc quod

More or less like grep abc * does.

Edit: I want to use this as a simple shell script. It would be great if the output is on one line, so further grepping would be possible. But it is not necessary that the script is only one line, i am putting it in a bash script file anyways.

Edit 2: Later I found "ack", which is a great tool and I use this now in most cases instead of grep. It does all this and more. http://betterthangrep.com/ You would write ack --php --nogroup abc to get the desired result

+6  A: 

Use the -H switch (man grep):

find . -name "*php" -exec grep -H abc {} \;

Alternative using xargs (now the -H switch is not needed, at least for the version of grep I have here):

find . -name "*php" -print | xargs grep abc


Edit: As a consequence of grep's behavior as noted by orsogufo, the second command above should use -H if find could conceivably return only a single filename (i.e. if there is only a single PHP file). If orsogufo's comment w.r.t. -print0 is also incorporated, the command becomes:

find . -name "*php" -print0 | xargs -0 grep -H abc

Edit 2: A (more1) POSIX compliant version as proposed by Jonathan Leffler, which through the use of /dev/null avoids the -H switch:

find . -name "*php" -print0 | xargs -0 grep abc /dev/null


1: A quote from the opengroup.org manual on find hints that -print0 is non-standard:

A feature of SVR4's find utility was the -exec primary's + terminator. This allowed filenames containing special characters (especially s) to be grouped together without the problems that occur if such filenames are piped to xargs. Other implementations have added other ways to get around this problem, notably a -print0 primary that wrote filenames with a null byte terminator. This was considered here, but not adopted. Using a null terminator meant that any utility that was going to process find's -print0 output had to add a new option to parse the null terminators it would now be reading.

Stephan202
The -H is not needed with xargs because grep is receiving more than one file on the command line, and in that case it outputs the file name along with the capture; I think it's a standard behavior, and should work also on greps different from yours. Note that it would better to use 'find ... -print0' and pipe the output to 'xargs -0', so that a 0-separator is used, and your command will work also with nasty file names (e.g. containing spaces).
Paolo Tedesco
Thank you for your comment. I updated the answer.
Stephan202
Note that the other way to deal with the possibility of one file being passed to grep is to add /dev/null to the command, so grep always has at least two files to search. The '-H' option for grep is not part of the POSIX specification - it is a useful GNU extension.
Jonathan Leffler
Interesting point. Updated the answer accordingly.
Stephan202
I Googled a bit, and I get the idea that -print0 is not POSIX compliant... see near the bottom of this page: http://www.opengroup.org/onlinepubs/009695399/utilities/find.html
Stephan202
+2  A: 

If you don't need to recursively search, you can just do..

grep -H abc *.php

..which gives you the desired output. -H is the default behaviour (at least on the OS X version of grep), so you can omit this:

grep abc *.php

You can grep recursively using the -R flag, but you're unable limit it to .php files:

grep -R abc *

Again, this has the same desired output.

I know this doesn't exactly answer your questions, it's just.. an alternative... The above are just grep with a single flag, so are easier to remember than find/-exec/grep/xargs combinations! (irrelevant for a script, but useful for day-to-day shell'ing)

dbr
+1  A: 
find /path -type f -name "*.php" | awk '
{
    while((getline line<$0)>0){
        if(line ~ /time/){
            print $0":"line
            #do some other things here
        }
    }    
}'
ghostdog74