Using linux find command to identify files that (A) match either of two names (with wildcards) and (B) that also contain a string - linux

The find command is really useful to identify files with a given name that also contain a string somewhere inside of them.
For instance lets say I'm looking for the string "pacf(" in an R markdown file somewhere in my current directory.
find . -name "*.Rmd" -exec grep -ls "pacf(" {} \;
I get useful results.
However, sometimes, I'm not sure if the file I am looking for is an .R file or a .Rmd file so I might also run.
find . -name "*.R" -exec grep -ls "pacf(" {} \;
And lets say there are no R files containing this string so that returns nothing.
One think I'd like to do is look in both .R and .Rmd files for this string. I would think that I could run
find . -name "*.Rmd" -o -name "*.R" -exec grep -ls "pacf(" {} \
But that returns no results.
However if I run
find . -name "*.R" -o -name "*.Rmd" -exec grep -ls "pacf(" {} \
I get the same results as just searching the .Rmd files. So it seems like it is only running the stuff in exec for the second set of files.
Is there a way I could change these commands to look through both the .R and .Rmd files at once?

Add parentheses '()'
find . \( -name '*.R' -o -name '*.Rmd' \) -exec grep -ls "pacf(" {} \;

you can pass "*[.Rmd]" for -name
like this
find . -name "*[.Rmd]" -exec grep -ls "pacf(" {} \;

Related

Find all files contained into directory named

I would like to recursively find all files contained into a directory that has name “name1” or name “name2”
for instance:
structure/of/dir/name1/file1.a
structure/of/dir/name1/file2.b
structure/of/dir/name1/file3.c
structure/of/dir/name1/subfolder/file1s.a
structure/of/dir/name1/subfolder/file2s.b
structure/of/dir/name2/file1.a
structure/of/dir/name2/file2.b
structure/of/dir/name2/file3.c
structure/of/dir/name2/subfolder/file1s.a
structure/of/dir/name2/subfolder/file2s.b
structure/of/dir/name3/name1.a ←this should not show up in the result
structure/of/dir/name3/name2.a ←this should not show up in the result
so when I start my magic command the expected output should be this and only this:
structure/of/dir/name1/file1.a
structure/of/dir/name1/file2.b
structure/of/dir/name1/file3.c
structure/of/dir/name2/file1.a
structure/of/dir/name2/file2.b
structure/of/dir/name2/file3.c
I scripted something but it does not work because it search within the files and not only folder names:
for entry in $(find $SEARCH_DIR -type f | grep 'name1\|name2');
do
echo "FileName: $(basename $entry)"
done
If you can use the -regex option, avoiding subfolders with [^/]:
~$ find . -type f -regex ".*name1/[^/]*" -o -regex ".*name2/[^/]*"
./structure/of/dir/name2/file1.a
./structure/of/dir/name2/file3.c
./structure/of/dir/name2/subfolder
./structure/of/dir/name2/file2.b
./structure/of/dir/name1/file1.a
./structure/of/dir/name1/file3.c
./structure/of/dir/name1/file2.b
I'd use -path and -prune for this, since it's standard (unlike -regex which is GNU specific).
find . \( -path "*/name1/*" -o -path "*/name2/*" \) -prune -type f -print
But more importantly, never do for file in $(find...). Use finds -exec or a while read loop instead, depending on what you really need to with the matching files. See UsingFind and BashFAQ 20 for more on how to handle find safely.

How can I make find pass file names to exec without the leading directory name?

Someone created directories with names like source.c. I am doing a find over all the directories in a tree. I do want find to search in the source.c directory, but I do not want source.c to be passed to the grep I am doing on what is found.
How can I make find not pass directory names to grep? Here is what my command line looks like:
find sources* \( -name "*.h" -o -name "*.cpp" -o -name "*.c" \) -exec grep -Hi -e "ThingToFind" {} \;
Add -a -type f to your find command. This will force find to only output files, not directories. (It will still search directories):
find sources* \( -name "*.h" -o -name "*.cpp" -o -name "*.c" \) -a -type f -exec grep -Hi -e "ThingToFind" {} \;

find -name "*.xyz" -o -name "*.abc" -exec to Execute on all found files, not just the last suffix specified

I'm trying to run
find ./ -name "*.xyz" -o -name "*.abc" -exec cp {} /path/i/want/to/copy/to
In reality it's a larger list of name extensions but I don't know that matters for this example. Basically I'd like to copy all those found to another /path/i/want/to/copy/to. However it seems to only be executing the last -name test in the list.
If I remove the -exec portion all the variations of files I expect to be found are printed out.
How do I get it to pass the full complement of files found to -exec?
find works by evaluating the expressions you give it until it can determine the truth value (true or false) of the entire expression. In your case, you're essentially doing the following, since by default it ANDs the expressions together.
-name "*.xyz" OR ( -name "*.abc" AND -exec ... )
Quoth the man page:
GNU find searches
the directory tree rooted at each given file name by evaluating the
given expression from left to right, according to the rules of precedence (see section OPERATORS), until the outcome is known (the left
hand side is false for and operations, true for or), at which point
find moves on to the next file name.
That means that if the name matches *.xyz, it won't even try to check the latter -name test or -exec, since it's already true.
What you want to do is enforce precedence, which you can do with parentheses. Annoyingly, you also need to use backslashes to escape them on the shell:
find ./ \( -name "*.xyz" -o -name "*.abc" \) -exec cp {} /path/i/want/to/copy/to \;
More usable than Jaypal's solution would maybe be:
find ./ -regex ".*\.\(jpg\|png\)" -exec cp {} /path/to
find . \( -name "*.xyz" -o -name "*.abc" \) -exec cp {} /path/i/want/to/copy/to \;
It may work:
find ./ -name "*.{xyz,abc}" -exec cp {} /path/i/want/to/copy/to

In Unix,cmd to search a file recursively and retrieve the file instead of just the path of the file

In Unix, what is the single cmd that lets me search and locate a file recursively and then retrieve the file instead of just the path of the file?
What do you mean by retrieve?
You can simply use -exec argument to find.
$ find /path/to/search -type f -name '*.txt' -exec cat {} \;
$ find /path/to/search -type f -name 'pattern' -exec cp {} /path/to/new \;
The second one should work.
cat `find /wherever/you/want/to/start/from -name name_of_file`
Note those quotes are backquotes (`).

How can I "clip" the output of the find command?

I executed the following command:
find / -type f -name fs-type -exec svnlook tree {} \; |egrep "/$"
The result was
svnlook: Can't open file '/var/lib/svn/repos/b1me/products/payone/generic/code/core/db/fs-type/format': Not a directory
svnlook: Can't open file '/var/lib/svn/repos/b1me/products/payone/generic/code/fees/db/fs-type/format': Not a directory
Maybe I should make find command give me the path without db/fs-type/format in other words I should clip the output of find. How can I do this?
First you can give
find ... -not -path "*/db/*"
to find.
This is what you're looking for
find Subversion -type d -name db -exec svnlook tree {}/.. \; | egrep "/$"
Your command was failing because svnlook expects a directory argument not a file one.

Resources