grep: search inside user include files - include

I want to search for string/expression in some c files using grep or find. Is there any ways to search in header files which is included in that c file?
eg:
myfile.c
#include <stdio.h>
#include "myfile1.h"
#include "myfile2.h"
void main()
{
DATA val;
}
Let I want to search for string "DATA". It should search in myfile.c and in myfile1.h,myfile2.h...

I think something like this might work:
grep -nr "DATA" path/to/files
n is to include the line number of the file that is matched
r is to search recursively on the path provided
You could also list each file specifically:
grep -nr "DATA" myfile.c myfile1.h myfile2.h
Or, if all your .h files are in the same directory:
grep -nr "DATA" *.h
Additionally, you can grep to get a list of included header files:
grep -o "\".*\.h\"" myfile.c
"myfile1.h"
"myfile2.h"
From there, you can use xargs to take those outputs and run the original search on each of the file names that are returned:
grep -o "\".*\.h\"" myfile.c | xargs grep -n "DATA"
include the original file in the search as well if you like:
grep -o "\".*\.h\"" myfile.c | xargs grep -n "DATA" myfile.c

write a shell script, like this
1) first search the word DATA in myfile.c
grep -nr "DATA" myfile.c
2) search for the words containing the extension .h
3) now again apply the grep commands to these header files
grep -nr "DATA" myfile1.h myfile2.h

Related

How to grep files in date order

I can list the Python files in a directory from most recently updated to least recently updated with
ls -lt *.py
But how can I grep those files in that order?
I understand one should never try to parse the output of ls as that is a very dangerous thing to do.
You may use this pipeline to achieve this with gnu utilities:
find . -maxdepth 1 -name '*.py' -printf '%T#:%p\0' |
sort -z -t : -rnk1 |
cut -z -d : -f2- |
xargs -0 grep 'pattern'
This will handle filenames with special characters such as space, newline, glob etc.
find finds all *.py files in current directory and prints modification time (epoch value) + : + filename + NUL byte
sort command performs reverse numeric sort on first column that is timestamp
cut command removes 1st column (timestamp) from output
xargs -0 grep command searches pattern in each file
There is a very simple way if you want to get the filelist in chronologic order that hold the pattern:
grep -sil <searchpattern> <files-to-grep> | xargs ls -ltr
i.e. you grep e.g. "hello world" in *.txt, with -sil you make the grep case insensitive (-i), suppress messages (-s) and just list files (-l); this you then pass on to ls (| xargs), sorting it by date (-t) showing date (-l) and all files (-a).

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

Grep out all file extensions from input

My input is a large list of files. They could have any characters in the name (including periods, because there are some package names as well). Here's some small sample input:
com.test.impl.servlets.Test.xml
TestClass.class
TestClass1.class
Test2.java
Test3.java
I want to know all of the different file extensions in my list, so essentially, I want egrep -o everything after the last period. Something like this:
input | xargs <unknown command but probably egrep> | sort -u
Would return:
.xml
.class
.java
You can try grep -o '\.[^.]*$':
$ echo 'com.test.impl.servlets.Test.xml
TestClass.class
TestClass1.class
Test2.java
Test3.java' | grep -o '\.[^.]*$' | sort -u
.class
.java
.xml
or sed 's/.*\././':
$ echo 'com.test.impl.servlets.Test.xml
TestClass.class
TestClass1.class
Test2.java
Test3.java' | sed 's/.*\././' | sort -u
.class
.java
.xml
If your make has pcre compiled in
$ grep -P -o '.*\.\K.*'

How can I find lines in one file but not the other using bash scripting?

Imagine file 1:
#include "first.h"
#include "second.h"
#include "third.h"
// more code here
...
Imagine file 2:
#include "fifth.h"
#include "second.h"
#include "eigth.h"
// more code here
...
I want to get the headers that are included in file 2, but not in file 1, only those lines.
So, when ran, a diff of file 1 and file 2 will produce:
#include "fifth.h"
#include "eigth.h"
I know how to do it in Perl/Python/Ruby, but I'd like to accomplish this without using a different programming language.
This is a one-liner, but does not preserve the order:
comm -13 <(grep '#include' file1 | sort) <(grep '#include' file2 | sort)
If you need to preserve the order:
awk '
!/#include/ {next}
FILENAME == ARGV[1] {include[$2]=1; next}
!($2 in include)
' file1 file2
If it's ok to use a temp file, try this:
grep include file1.h > /tmp/x && grep -f /tmp/x -v file2.h | grep include
This
extracts all includes from file1.h and writes them to the file /tmp/x
uses this file to get all lines from file2.h that are not contained in this list
extracts all includes from the remainder of file2.h
It probably doesn't handle differences in whitespace correctly etc, though.
EDIT:
to prevent false positives, use a different pattern for the last grep (thanks to jw013 for mentioning this):
grep include file1.h > /tmp/x && grep -f /tmp/x -v file2.h | grep "^#include"
This variant requires an fgrep with the -f option. GNU grep (i.e. any Linux system, and then some) should work fine.
# Find occurrences of '#include' in file1.h
fgrep '#include' file1.h |
# Remove any identical lines from file2.h
fgrep -vxf - file2.h |
# Result is all lines not present in file1.h. Out of those, extract #includes
fgrep '#include'
This does not require any sorting, nor any explicit temporary files. In theory, fgrep -f could use a temporary file behind the scenes, but I believe GNU fgrep doesn't.
If the goal need not be accomplished with Bash alone (i.e., use of external programs is acceptable), then use combine from moreutils:
combine file1 not file2 > lines_in_file1_not_in_file2
cat $file1 $file2 | grep '#include' | sort | uniq -u

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