I want to make a script that can do the following automatically:
grep 'string1' file.txt | grep 'string2' | grep 'string3' ... | grep 'stringN'
The idea is that the script can be run like this:
myScript.sh file.txt string1 string2 string3 ... stringN
and the script has to return all the lines of file.txt
that contain all the strings.
For instance, if file.txt
looks like this:
hello world
hello world run
hello planet world
And I can make a grep like this:
grep hello file.txt | grep world
and I get:
hello world
hello world run
hello planet world
I want to make a script that makes this automatically, with an undefined number of strings as parameters.
I found that it is hard to achieve this, since the number of strings can be variable. First, I tried to create an array called args
like this in myScript.sh
:
#!/bin/bash
args=("$@")
with the purpose of storing the arguments. I know that the ${args[0]}
is going to be my file.txt
and the rest are the strings that I need to use in the distinct greps, but I don't know how to proceed and if this is the best approach to solve the problem. I would appreciate any suggestion about how to program this.
You can create the command in a loop and then use
eval
to evaluate it. This is usingcat
so you can group all thegrep
.An eval-free alternative:
mktemp
generates a temporary file with a unique name and returns its name; it should be widely available.The loop then executes
grep
for each argument and renames the second temp file for the next loop.This is the optimization of Diego Torres Milano's code and the answer to my original question:
You can generate the pattern of operation and save it in a variable:
and then
Example:
sed
is capable of doing this perfectly with a single process, and avoids theseeval
shenanigans. The resulting script is actually quite simple.We generate a line of
sed
script for each expression; if the expression is not (!
) found, we delete (d
) this input line, and start over with the next one.This assumes your
sed
accepts-
as the argument to-f
to read the script from standard input. This is not completely portable; you would perhaps need to store the generated script in a temporary file instead if this is a problem.This uses
?
as the internal regex separator. If you need a literal?
in one of the patterns, you will need to backslash-escape it. In the general case, creating a script which finds an alternative separator which is in none of the search expressions would perhaps be possible, but at that point, I'd move to a proper scripting language (Python would be my preference) instead.