Printing results common to many grep - bash

How can I use two grep statements and print only those files which satisfy both the grep searches....
OR
How can I look for two different String in a file and print the contents of the file if it contain both the Strings ?

Something like this should get you started:
pattern1=your-pattern
pattern2=your-pattern
basedir=/path/to/dir
grep -Zlr "$pattern1" "$basedir" | xargs -0 grep -l "$pattern2"
The key elements:
The -l flag is to print the names of files that matched.
The -Z flag is to output a null-byte after matched filenames
xargs -0 will expect null terminated items in its input
The first grep will find files matching pattern1, the second grep will find files matching pattern2 -> the end result is a list of files matching both patterns.

Related

Bash how pipe sort, find and grep

I'm trying to write a shell script that take the a line of a file that contain a specific number, the problem is that i need this file sorted because i need the line of the last file with some specific name.
I have write this code but it seems doesn't work
sort -n | find -name '*foo*' -exec grep -r -F '11111' {} \;
Is really important that the files are sorted because i need to search in the last file. The files name are of type "res_yyyy_mm_dd_foo" and they have to be ordered by yyyy and if are the same by mm and so
Sounds like the following would do it:
cd home/input_output.1/inp.1/old_res23403/
ls -1 | sort -r | xargs cat -- | grep '11111' | head -n1
ls -1 produces a list of filenames in the current directory, one per line.
sort -r sorts them in reverse alphabetical order, which (given that your names use a big-endian date format) puts the latest files first.
xargs cat -- concatenates the contents of all those files.
grep '11111' finds all lines containing 11111.
head -n1 limits results to the first such line.
In effect this gives you the first matching line of the files in reverse order, i.e. the last such line.

Grep to Print all file content [duplicate]

This question already has answers here:
Colorized grep -- viewing the entire file with highlighted matches
(24 answers)
Closed 4 years ago.
How can I modify grep so that it prints full file if its entry matches the grep pattern , instead of printing Just the matching line ?
I tried using(say) grep -C2 to print two lines above and 2 below but this doesn't always works as no. of lines is not fixed ..
I am not Just searching a single file , I am searching an entire directory where some files may contain the given pattern and I want those Files to be completely Printed.
I am also using grep inside grep result without getting printed the first grep output.
Simple grep + cat combination:
grep 'pattern' file && cat file
Use grep's -l option to list the paths of files with matching contents, then print the contents of these files using cat.
grep -lR 'regex' 'directory' | xargs -d '\n' cat
The command from above cannot handle filenames with newlines in them.
To overcome the filename with newlines issue and also allow more sophisticated checks you can use the find command.
The following command prints the content of all regular files in directory.
find 'directory' -type f -exec cat {} +
To print only the content of files whose content matches the regexes regex1 and regex2, use
find 'directory' -type f \
-exec grep -q 'regex1' {} \; -and \
-exec grep -q 'regex2' {} \; \
-exec cat {} +
The linebreaks are only for better readability. Without the \ you can write everything into one line.
Note the -q for grep. That option supresses grep's output. grep's exit status will tell find whether to list a file or not.

Input redirection to grep

I have a directory with contents like this -
vishal.yadav#droid36:~/Shell$ ls
lazy_dog.txt ls-error.txt ls-output.txt ShellCommands.txt TheTimeMachineHGWells.txt words.txt words.txt.bak
First Command
If I try using ls | grep *.txt I get the following output -
ShellCommands.txt: $ cat > lazy_dog.txt
ShellCommands.txt: $ cat lazy_dog.txt
ShellCommands.txt: $ cat < lazy_dog.txt
ShellCommands.txt:input from the keyboard to the file lazy_dog.txt. We see that the result is the
Second Command
And if I use ls | grep .*.txt I get this as output -
lazy_dog.txt
ls-error.txt
ls-output.txt
ShellCommands.txt
TheTimeMachineHGWells.txt
words.txt
words.txt.bak
Isn't .*.txt and *.txt one and the same?
In the First Command, is the output of ls the regex for grep or is it the list of files?
Similarly, for the Second Command, is the output of ls the regex or list of files?
In the first command (ls | grep *.txt), the output from ls is completely ignored by grep because it sees:
grep lazy_dog.txt ls-error.txt ls-output.txt ShellCommands.txt TheTimeMachineHGWells.txt
It has one pattern lazy_dog.txt and four files, so it reads each file in turn to find the pattern, and prefixes the matching output lines with the name of the file that held the pattern. If there was only one file name, it would not list the file name before the matched lines.
It appears that the only file of the four that grep searches (ls-error.txt, ls-output.txt, ShellCommands.txt, TheTimeMachineHGWells.txt) that contains the text lazy_dog.txt is ShellCommands.txt, so that's what you see in the output. Note that a line containing lazy_dogstxt would also match the regex (but not the shell glob).
In the second command (ls | grep .*.txt), there are no files that match .*.txt, so that argument is passed to grep unexpanded, so it has only a pattern, so it reads its standard input, which is the output from ls this time. All the file names match the regex .*.txt (even though none of them match the shell glob .*.txt), so they're all listed. Note that it would also pick up many other lines, even one containing just "etxt", because the . is a grep metacharacter (and the .*.txt regex matches any string of zero or more characters followed by one arbitrary character and then txt.
do ls -al:
you will find that the current directory is listed as a . and previous directory is listed as ...
So when you say ls | grep .*.txt, the . is taken as path matching from current directory that contains .txt afterwards.
grep see the pattern .*.txt as regex, not glob.
So you can use ls *.txt or ls | grep .*txt

How to grep return result as the matching term

I would like to return only the first instance (case-insensitive) of the term I used to search (if there's a match), how would I do this?
example:
$ grep "exactly-this"
Binary file /Path/To/Some/Files/file.txt matches
I would like to return the result like:
$ grep "exactly-this"
exactly-this
grep has an inbuilt count argument
You can use the -m option to give a count argument to grep
grep -m 1 "exactly-this"
If you want to avoid the message in case of the binary files,use
grep -a -m 1 "exactly-this"
Note that this will print the word in which the match occurred.Since it is a binary file,the word may span over multiple lines
What you need is the -o option of grep.
From the man page
-o, --only-matching
Prints only the matching part of the lines.
Test:
[jaypal:~/Temp] cat file
This is a file with some exactly this in the middle
with exactly this in the begining
and some at the very end in brackets (exactly this)
[jaypal:~/Temp] grep -o 'exactly this' file
exactly this
exactly this
exactly this
[jaypal:~/Temp] grep -om1 'exactly this' file
exactly this

How do I grep the contents of files returned by grep?

When I look for log files with an error message using grep error *log, it returns a list of logfiles
$grep error *log
Binary file out0080-2011.01.07-12.38.log matches
Binary file out0081-2011.01.07-12.38.log matches
Binary file out0082-2011.01.07-12.38.log matches
Binary file out0083-2011.01.07-12.38.log matches
However, these are text, not binary files.
I am not sure why these are considered binary, the first few lines contain the following non-error messages:
out0134
-catch_rsh /opt/gridengine/default/spool/compute-0-17/active_jobs/327708.1/pe_hostfile
compute-0-17
I would like to grep the contents of the returned files for an error message and return the names of the files with the message.
How can I grep the contents of the returned files, rather than this list of returned files, as happens with grep error *log | grep foo?
Here's the answer you might be looking for:
grep -l foo $(grep -l error *.log)
-l tells grep to print filenames only; that does the first grep, then substitutes the result into the next grep's command. Alternatively, if you like xargs:
grep -l error *.log | xargs grep -l foo
which does the same thing, using xargs to call the second grep with the first grep's results as arguments.
-a, --text
Process a binary file as if it were text; this is equivalent to
the --binary-files=text option.
grep -a "some error message" *.log
Btw, here is how grep determines binary from text files
If the first few bytes of a file
indicate that the file contains binary
data, assume that the file is of type
TYPE. By default, TYPE is
binary...
Update
If you want just a list of file names which contain the word foo within the line that also contains error then you can do one or the other of these:
grep -la "error.*foo" *.log <-- assumes foo comes after error
I do this.
$find . -type f -name *.log | fgrep -v
[anything unwanted] | xargs grep -i
[search inside files]
A comment asked about how to only grep for foo in the files that match the error, you can:
for i in *log ; do
grep -a error $i >/dev/null 2>&1 && {
echo -e "File $i:\n\t"
grep -a foo $i
}
done

Resources