What's the Best Way to Find a String/Regex Match in Files Recursively? (Unix)

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


grep -r REGEX .

Replace . with whatever directory you want to search from.

How do I recursively grep all directories and subdirectories?


grep -r "texthere" .

The first parameter represents the regular expression to search for, while the second one represents the directory that should be searched. In this case, . means the current directory.

Note: This works for GNU grep, and on some platforms like Solaris you must specifically use GNU grep as opposed to legacy implementation. For Solaris this is the ggrep command.

How to find all files containing specific text (string) on Linux?

Do the following:

grep -rnw '/path/to/somewhere/' -e 'pattern'
  • -r or -R is recursive,
  • -n is line number, and
  • -w stands for match the whole word.
  • -l (lower-case L) can be added to just give the file name of matching files.
  • -e is the pattern used during the search

Along with these, --exclude, --include, --exclude-dir flags could be used for efficient searching:

  • This will only search through those files which have .c or .h extensions:
grep --include=\*.{c,h} -rnw '/path/to/somewhere/' -e "pattern"
  • This will exclude searching all the files ending with .o extension:
grep --exclude=\*.o -rnw '/path/to/somewhere/' -e "pattern"
  • For directories it's possible to exclude one or more directories using the --exclude-dir parameter. For example, this will exclude the dirs dir1/, dir2/ and all of them matching *.dst/:
grep --exclude-dir={dir1,dir2,*.dst} -rnw '/path/to/somewhere/' -e "pattern"

This works very well for me, to achieve almost the same purpose like yours.

For more options, see man grep.

Recursively find all files that match a certain pattern

With gnu find you can use regex, which (unlike -name) match the entire path:

find . -regex '.*/foo/[^/]*.doc'

To just count the number of files:

find . -regex '.*/foo/[^/]*.doc' -printf '%i\n' | wc -l

(The %i format code causes find to print the inode number instead of the filename; unlike the filename, the inode number is guaranteed to not have characters like a newline, so counting is more reliable. Thanks to @tripleee for the suggestion.)

I don't know if that will work on OSX, though.

Recursive find and replace based on regex

It's hard to tell exactly what you want because your refactoring example changes the import as well as the package, but the following will change common. -> etc.common. for all files in a directory:

sed -i 's/\bcommon\./etc.&/' $(egrep -lr '\bcommon\.' .)

This assumes you have gnu sed available, which most linux systems do. Also, just to let you know, this will fail if there are too many files for sed to handle at one time. In that case, you can do this:

egrep -lr '\bcommon\.' . | xargs sed -i 's/\bcommon\./etc.&/'

Note that it might be a good idea to run the sed command as sed -i'.OLD' 's/\bcommon\./etc.&/' so that you get a backup of the original file.

Grep returning regex results in recursive search

You can try the -a option:

File and Directory Selection
-a, --text
Process a binary file as if it were text; this is equivalent to
the --binary-files=text option.

--binary-files=TYPE
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, and grep normally outputs either a one-line
message saying that a binary file matches, or no message if
there is no match. If TYPE is without-match, grep assumes that
a binary file does not match; this is equivalent to the -I
option. If TYPE is text, grep processes a binary file as if it
were text; this is equivalent to the -a option. Warning: grep
--binary-files=text might output binary garbage, which can have
nasty side effects if the output is a terminal and if the
terminal driver interprets some of it as commands.

But the problem is that in binary files there are no lines, so I'm not sure what you'd want the output to look like. You'll see random garbage, maybe the whole file, some special characters messing with your terminal may be printed.

If you want to restrict the output to the match itself, consider the -o option:

   -o, --only-matching
Print only the matched (non-empty) parts of a matching line,
with each such part on a separate output line.

The context control is limited to adding a certain number of lines before or after the match, which will probably not work well here. So if you want a context of certain number of bytes, you'll have to change the pattern itself.

regex match either string in linux find command

Say:

find . \( -name "*.py" -o -name "*.py.server" \)

Saying so would result in file names matching *.py and *.py.server.

From man find:

   expr1 -o expr2
Or; expr2 is not evaluated if expr1 is true.

EDIT: If you want to specify a regex, use the -regex option:

find . -type f -regex ".*\.\(py\|py\.server\)"

Unix command to search and replace text recursively


Also are there any alternate commands that provides same functionality in Unix

Yes you can do all this in find itself:

find ./myFolder -type f -exec sed -i 's/Application/whatever/g' '{}' \;

-exec option in find is for:

-exec utility [argument ...] ;

True if the program named utility returns a zero value as its exit status. Optional arguments may be passed to the utility.
The expression must be
terminated by a semicolon ('';''). If you invoke find from a shell you may need to quote the semicolon if the shell would
otherwise treat it as a
control operator. If the string ''{}'' appears anywhere in the utility name or the arguments it is replaced by the pathname of
the current file.
Utility will be executed from the directory from which find was executed. Utility and arguments are not subject to the
further expansion of shell
patterns and constructs.

How can I recursively find all files in current and subfolders based on wildcard matching?

Use find:

find . -name "foo*"

find needs a starting point, so the . (dot) points to the current directory.



Related Topics



Leave a reply



Submit