How would you do a search from the unix shell with both constraints on the filename and the file content? - linux

Can find perform full-text search? How would you do a search with both some constraints on the filename and the file content?

find . -name whatever -print | xargs grep whatever
Add "-l" option to grep to just get filenames.

I would strongly recommend getting hold of ack and using it for any findy-greppy-type-stuff that you want to do - I use it every day and can't imagine how I lived without it! In this case it sounds like ack -G <file-regex> <text-regex> would do what you want.

find -name whatever -exec grep --with-filename you_search_for_it {} \;
{} contains the file name returned by find
\; to terminate the find command

In some cases globbing will provide enough constraints on your filenames:
shopt -s nullglob # Bash: prevents "No such file or directory" errors
grep string {.,[jm]*,{one,two}}/{[a-c],[hlz]}?{earth,mars,venus}[[:ascii:]]*atm*.dat
which would search files such as:
./bZmars_321atmBB111.dat
m42a/z3venus-a18atm9.dat
two/aaearth+GHIatm9876.dat

Related

Using "grep" to search for specific type of files in all subdirectories

I am trying to find a specific line in files that contains "Mutual_Values_23.0" in a directory that contains a lot of subdirectories. I know this line number is stored in a file which starts with "gnuout_mutual_....txt" (the ellipses part of the file name is the time stamp so that varies).
I wanted to know if there is a way to specify "grep" command to look into the subdirectories only for the files starting with "gnuout_mutual_....txt"
I have tried
grep -r "Mutual_Values_23.0" *
but that's taking a long time
You can use the following option of grep:
--include=GLOB
Search only files whose base name matches GLOB (using wildcard matching as described under --exclude).
And for the line number you should use the -n option.
From within the root of the folders you want to look into, you can use this final command:
grep -nr "Mutual_Values_23.0" --include="gnuout_mutual_*txt"
Use find to search all sub-directories for the "gnuout...txt` file with the search string "Mutual_Values_23.0"
find . -mindepth 1 -name gnuout_mutual_\*.txt -type f -exec grep "Mutual_Values_23.0" {} +
If you make use of bash, you can use the globstar option:
globstar
If set, the pattern ** used in a pathname expansion context will
match all files and zero or more directories and subdirectories.
If the pattern is followed by a /, only directories and
subdirectories match.
So you can use it like:
$ shopt -s globstar
$ grep "search_string" **/glob-pattern
or in the case of the OP:
$ shopt -s globstar
$ grep Mutual_Values_23.0 **/gnuout_mutual_*.txt
GNU grep has the --include GLOB option where GLOB can be used to specify the file name pattern that you need to match.
grep -rn --include 'gnuout_mutual_*txt' 'Mutual_Values_23.0' .
You could use find to search for files and pass results to grep.
find /directory_where_to_search/ -iname 'gnuout_mutual_*.txt' | xargs grep 'Mutual_Values_23.0' -sl
Use this command:
$ find . -name "*Mutual_Values_23.0*"
Note: Run this command in the directory where you want to search your set of files.
Hope it helps, cheers!

Search a word into all makefiles linux from terminal

I'm using Ubuntu. I have to search the word "send" into multiple makefiles.
Suppose that all makefiles are into /home/mypath. I tried this command but doesn't work. Could you please help me? Thanks in advance.
find /home/mypath/ -name Makefile && grep -r "send"
You can use the below command to find for send keyword in all the Makefiles
recursively.
find /home/mypath -name "Makefile" | xargs grep -r "send"
Here the find command list all the files with name Makefile under the specified directory. xargs command will pass all the files listed with serially to the grep command to search for the string send
If your base path is the same, you can use grep only:
grep -rn --color "send" /home/mypath/Makefile
The find command has an option to transfer the found file name to an exec command which is here grep. Important is that you give {} which will be replaced with the filename found by find. You need also the \; as end mark of your command given for the ' -exec' option for find.
find /home/mypath -name Makefile -exec grep "what you search" {} \;

Search and replace entire files

I've seen numerous examples for replacing one string with another among multiple files but what I want to do is a bit different. Probably a lot simpler :)
Find all the files that match a certain string and replace them completely with the contents of a new file.
I have a find command that works
find /home/*/public_html -name "index.php" -exec grep "version:1.23" '{}' \; -print
This finds all the files I need to update.
Now how do I replace their entire content with the CONTENTS of /home/indexnew.txt (I could also name it /home/index.php)
I emphasize content because I don't want to change the name or ownership of the files I'm updating.
find ... | while read filename; do cat static_file > "$filename"; done
efficiency hint: use grep -q -- it will return "true" immediately when the first match is found, not having to read the entire file.
If you have a bunch of files you want to replace, and you can get all of their names using wildcards you can try piping output to the tee command:
cat my_file | tee /home/*/update.txt
This should look through all the directories in /home and write the text in my_file to update.txt in each of those directories.
Let me know if this helps or isn't what you want.
I am not sure if your command without -l and then print it is better than to add -l in grep to list file directly.
find /home/*/public_html -name "index.php" -exec grep -l "version:1.23" '{}' \; |xargs -i cp /home/index.php {}
Here is the option -l detail
-l, --files-with-matches
Suppress normal output; instead print the name of each input
file from which output would normally have been printed. The
scanning will stop on the first match. (-l is specified by
POSIX.)

grep recursive exclusive search

I have text I want to recursively search in mydir/. I would normally type grep -r "text to find" mydir/" but what would I type if I wanted to search all the files except a specific one?
For example, I do not want to search the file "myfile.txt" but it is contained in the directory.
What would I type?
One quick way is to use BASH's extended file globbing.
There is an extended negation glob that you can use as follows:
shopt -s extglob
grep -r "text to find" !(myfile.txt)
Another more flexible method is to use a combination of find and xargs. Use find to filter out only the files you want, and xargs to pass them as arguments to grep.
Something like the following sould work:
find -type f -not -name myfile.txt | xargs grep "text to find"
You can use the following command to exclude a file:
grep -r --exclude="myfile.txt" "text to find"

What's the best way to find a string/regex match in files recursively? (UNIX)

I have had to do this several times, usually when trying to find in what files a variable or a function is used.
I remember using xargs with grep in the past to do this, but I am wondering if there are any easier ways.
grep -r REGEX .
Replace . with whatever directory you want to search from.
The portable method* of doing this is
find . -type f -print0 | xargs -0 grep pattern
-print0 tells find to use ASCII nuls as the separator and -0 tells xargs the same thing. If you don't use them you will get errors on files and directories that contain spaces in their names.
* as opposed to grep -r, grep -R, or grep --recursive which only work on some machines.
This is one of the cases for which I've started using ack (http://petdance.com/ack/) in lieu of grep. From the site, you can get instructions to install it as a Perl CPAN component, or you can get a self-contained version that can be installed without dealing with dependencies.
Besides the fact that it defaults to recursive searching, it allows you to use Perl-strength regular expressions, use regex's to choose files to search, etc. It has an impressive list of options. I recommend visiting the site and checking it out. I've found it extremely easy to use, and there are tips for integrating it with vi(m), emacs, and even TextMate if you use that.
If you're looking for a string match, use
fgrep -r pattern .
which is faster than using grep.
More about the subject here: http://www.mkssoftware.com/docs/man1/grep.1.asp
grep -r if you're using GNU grep, which comes with most Linux distros.
On most UNIXes it's not installed by default so try this instead:
find . -type f | xargs grep regex
If you use the zsh shell you can use
grep REGEX **/*
or
grep REGEX **/*.java
This can run out of steam if there are too many matching files.
The canonical way though is to use find with exec.
find . -name '*.java' -exec grep REGEX {} \;
or
find . -type f -exec grep REGEX {} \;
The 'type f' bit just means type of file and will match all files.
I suggest changing the answer to:
grep REGEX -r .
The -r switch doesn't indicate regular expression. It tells grep to recurse into the directory provided.
This is a great way to find the exact expression recursively with one or more file types:
find . \\( -name '\''*.java'\'' -o -name '\''*.xml'\'' \\) | xargs egrep
(internal single quotes)
Where
-name '\''*.<filetype>'\'' -o
(again single quotes here)
is repeated in the parenthesis ( ) for how many more filetypes you want to add to your recursive search
an alias looks like this in bash
alias fnd='find . \\( -name '\''*.java'\'' -o -name '\''*.xml'\'' \\) | xargs egrep'

Resources