3

I've gotten used to using grep for my command line searches and wanted to know how to successfully do a search using the result of another search.

Here's my attempt, where I am looking for 'tool' within my result:

grep tool | grep -rl embed=

This returns some results and then the console hangs. Are there any simple/elegant solutions to this?

  • 1
    Your console hangs, because the first grep needs a file (or stdin using a pipe) to read from. – polym Apr 11 '16 at 16:55
  • 1
    I could not quite understand what you are trying to accomplish with this command. First part, i.e., grep tool is looking for word tool in the stdin, then you are looking for file names, recursively, contaning keyword embed=. This can not possibly yield anything for you. If you haven't thought about it, second grep is taking first one's output as its input. If that input is just lines, -r or -l switches are irrelevant. – MelBurslan Apr 11 '16 at 16:58
  • @MelBurslan thanks, so in the second grep (in this wrong example), where does the first grep's output get used? Which order does everything happen? – darkace Apr 11 '16 at 22:47
  • Please see my answer below and if necessary modify your question with what you are trying to do, in plain English. Because it still doesn't make a lick of sense to me. – MelBurslan Apr 11 '16 at 23:07
  • 1
    Are you familiar with the concepts of stdin and stderr? – Xiong Chiamiov Apr 11 '16 at 23:39
6

Pipelines run from left to right. More precisely, the processes run in parallel, but the data flows from left to right: the output of the command on the left becomes the input of the command on the right.

Here the command on the left is grep tool. Since you're passing a single argument to grep, it's searching in its standard input. Since you haven't redirected the standard input, grep is reading from the terminal: it's waiting for you to type.

To search in a file, use

grep tool path/to/file | …

To search in a directory recursively, use

grep -r tool path/to/directory | …

You can filter the results to list only the lines that contain embed=. Drop the -l and -r options, they make no sense when the input is coming from standard input.

grep -r tool path/to/directory | grep 'embed='

This lists lines containing both tool and embed= (in either order). An alternative method with simpler plumbing would be to do a single search with an or pattern; this is always possible, but if the patterns can overlap (not the case here), the pattern can get very complicated.

grep -E -r 'tool.*embed=|embed=.*tool' path/to/directory

If you wanted to list files containing both tool and embed=, you'd need a different command structure, with the first grep listing file names (-l) and the second one receiving those file names as arguments, not as input. Converting standard input into command line arguments what the xargs command is for.

grep -lZ -r tool path/to/directory | xargs -0 grep -l 'embed='
  • For a POSIX way to do the last command, you could use find path/to/directory -type f -exec grep -q tool {} \; -exec grep -l embed= {} + – Wildcard Apr 11 '16 at 23:51
  • Also, I wish I could upvote this more than once—it is the only answer that actually answers the OP's use case and addresses his obvious confusion about left to right. – Wildcard Apr 11 '16 at 23:52
4

This command is going to search for foo in the file filename and in the results for bar:

grep foo filename | grep bar

An alternative would be with awk: awk '/foo/ && /bar/' filename

2

You can use grep in different ways, for instance:

cat myfile | grep keyword

This above example will dump the file to stdout. The pipe character | will take that output and feed it to grep keyword command as stdin. In the end, the lines in myfile containing keyword will be written to the stdout, which is generally terminal screen. This is a very ineffective use of resources, the same result can be accomplished with this command as well:

grep keyword myfile

if you want to use grep in a cascaded menner, here is how it goes:

grep keyword1 myfile | grep keyword2

This time, first grep command, finds the lines containing keyword1 in myfile. Second grep command takes the output of the first one, and searches for keyword2 in those. Effectively, you are looking for lines containing both keyword1 and keyword2 in myfile.

you can multiply these commands with different command line switches to find what exactly you are looking for, using more than one pipe. If you can elaborate what you are trying to do with your command in the original question in plain English, myself or someone else can help you further.

1

Essentially what you are trying to do is logical AND. grep is a line matching tool, so in terms of a line patter1 AND patter2 logic mean they are going to be on the same line ; when you search a file , where you want to find line with one term and another on the same line, you can use regular expression grep 'pattern1.*pattern2' input_file.txt

$ ps -ef | grep 'xieerqi.*firefox'
xieerqi   5069  2616  7 17:43 ?        00:07:25 /usr/lib/firefox/firefox
xieerqi  24317  6901  0 19:22 pts/19   00:00:00 grep xieerqi.*firefox

In this example, instead of searching all processes with my username and then piping to another grep that filters firefox processes.

For more, refer to this tutorial

  • This solution only finds lines with the patterns in that order. – Jakob Lenfers Apr 12 '16 at 4:41
  • @JakobLenfers That's a valid point , but one can always repeat the search reversing the order or using the pattern1|pattern2 structure. Actually, I just realized that Gilles already proposed the same solution, using or and reversing the order of the pattern. Typically what users do is two pipes to grep , so cases where people use multiple patterns to search is not so frequent. So that's an OK solution, but for more patterns probably awk is better – Sergiy Kolodyazhnyy Apr 12 '16 at 5:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.