[linux find cmd]: limit the find command to search directories matching a given word or regex - linux

Can I limit the find command to search directories matching a given regex only?
I looked at
$ man find
but couldn't find any --include-directories option.
Using RHEL GNU/Linux.
Thanks.

One way you can try is :
find . ! \( -name . -o -regex ".*/dir" \) -prune -name file
The problem for this solution is you have to include starting directory (. in this case)
-prune means to exclude all directories except . or .*/dir

Related

Replace a file if path of the file contains a string in Linux [duplicate]

I know how to find files using
find . -name "file_name"
But if I am given one part of a path, say "folder1/subfolder2/", how do I get all the full path that contains this partial path?
Example
partial path: folder1/subfolder2/
desire result:
/bob/folder1/subfolder2/yo/
/sandy/folder1/subfolder2/hi/
Use the -path option:
find . -path '*/folder1/subfolder2/*'
You may do it like below:
find . -path "*folder1/folder2" -prune -exec find {} -type f -name file.txt \;
With -prune you don't recurse after first match in a directory
This one worked for me (using bash)
ls -l /**/folder1/subfolder2/**
I came up with this, other solutions did not work for me,
find1 is a function
find1 ()
{
for file in `find -name $1`;
do
full_path=$PWD/$file;
echo $full_path;
done
}
If you dont want to stay posix-compliant, at least on Linux you can also use the -regex (and -regextype) option for this purpose.
For instance:
find folder/ -regextype posix-extended -regex "(.*/)?deer/(.*/)?beer"
will match
folder/deer/beer
folder/deer/dir/forest/beer/
folder/forest/deer/dir/forest/beer/
etc.
See linux man for details.

Exclude range of directories in find command

I have directory called test which has sub folders in the date range like 01,02,...31. This all sub folders contain .bz2 files in it. I need to search all the files with .bz2 extension using find command but excluding particular range of directories. I know about find . -name ".bz2" -not -path "./01/*", but writing -not -path "./01/*" would be so pathetic if I would want to skip 10 directories. So how would I skip 01..19 subdirectories in my find command ?
You can use wildcards in the pattern for the option -not -path:
find ./ -type f -name "*.bz2" -not -path "./0*/*" -not -path "./1*/*
this will exclude all directories starting with 0 or 1. Or even better:
find ./ -type f -name "*.bz2" -not -path "./[01]*/*"
Firstly, you can help find by using -prune rather than -not -path - that will avoid even looking inside the relevant directories.
To your main point - you can build a wildcard for your example (numeric 01 to 19):
find . -path './0[1-9]' -prune -o -path './1[0-9]' -prune -o -print
If your range is less convenient (e.g. 05 to 25) you might want to build the range into a bash variable, then interpolate that into the find command:
a=("-path ./"{05..25}" -prune -o")
find . ${a[*]} -print -prune
(you might want to echo "${a[*]}" or printf '%s\n' ${a[*]} to see how it's working)
For me, I found the find command as a standalone tool somehow cumbersome. Therefore, I always end up using a combination of find just for the recursive file search and grep to make the actual exculsion/inclusion stuff. Finally I hand over the results to a third command which will perform the actions, like rm to remove files for example.
My generic command would look something like this:
find [root-path] | grep (-v)? -E "cond1|cond2|...|condN" | [action-performing-tool]
root-path is where to start the search recursively
add -v option is used to invert the matching results.
cond1 - condN, the conditions for the matching. When -v is involed then this are the conditions to not match.
the action-performing-tool does the actual work
For example you want to remove all files not matching some conditions in the current directory:
find . -not -name "\." | grep -v -E "cond1|cond2|cond3|...|condN" | xargs rm -rf
As you can see, we are searching in the current directory indicated by the dot as root-path: then we want to invert the matching results, because we want all files not matching our conditions: and finally we pass all files found to rm in order to delete them: I add -rf to recursive/force delete all files. I used the find command with -not -name "." to exclude the current directory indicated normally by dot.
For the actuall question: Assume we have a directory using .git and .metadata directory and we want to exclude them in our search:
find . -not -name "\." | grep -v -E ".git|.metadata" | [action-performing-tool]
Hope that helps!
If you wan to exclude child directory under parent directory then this might be useful:
E.g.- You have parent directory "ParentDir" and it has two child directories "Child1, Child2". You wan to read files from "Chiled2" only and skip "Child1". Then this will help.
find ./ParentDir ! -path "./ParentDir/Child1*" -name *.<extention>

How do I find files/directories that are executable by anybody?

I'm trying to find all files or directories that can be executed by EITHER user, group, or other. So far I have come up with this
find . -perm -u+x
I do not know how to search for group and other as well. I know that
find .-perm -ugo+x
will search for files/directories that can be executed by all 3 of those (essentially a+x).
I have searched and cannot figure out how to look for any of those 3. One place suggested
find . -perm -u+x, g+x, o+x
but i get the error
find: -perm: u+x,: illegal mode string
any ideas?
try this :
find . -perm /u=x,g=x,o=x
The POSIX-conformant syntax would be
find . \( -perm u=x -o -perm g=x -o -perm o=x \)
Each of the three -perm primaries checks if the file is executable by user, group, or other; they are joined by -o so that only one has to be true for the entire \(...\) group to be true.

find command search pattern

I have below 4 files
a_ROLLBACK2to3__test.sql,
a_1to2__test.sql,
a_2to3__test.sql,
a_2to2__test.sql
I want to write a find command to return the files a_1to2__test.sql, a_2to3__test.sql and a_2to2__test.sql, the file a_ROLLBACK2to3__test.sql should not be included in the search.
my find command looks like
find . -name "*_*to*__*.sql"
but this returns all files but I don’t want a_ROLLBACK2to3__test.sql.
basically the files with ROLLBACK after the first _ should not be included..
Can anyone help me to write the search pattern for my requirement?
Thanks
Simply filter the results with grep:
find . -name '*_*to*__*.sql' | grep -v ROLLBACK
Or use the AND clause -a with negation !:
find . -name '*_*to*__*.sql' -a ! -name '*ROLLBACK*'
You could simply look for the underscore followed by a digit:
find . -name '*_[0-9]*to*__*.sql'
or for an underscore not followed by R:
find . -name '*_[!R]*to*__*.sql'

how to exclude all subdirectories of a given directory in the search path of the find command in unix

I need to backup all the directory hierarchy of our servers, thus I need to list all the sub directories of some of the directories in the server.
The problem is that one of those sub directories contains tens of thousands of sub directories (file with only the names of the sub directories could take couple of hundreds megabytes and the respective find command takes very long).
For example, if I have a directory A and one sub directory A/a that contains tens of thousands of sub directories, I want to use the find command to list all the sub directories of A excluding all the sub directories of A/a but not excluding A/a itself.
I tried many variations of -prune using the answers in this question to no avail.
Is there a way to use the find command in UNIX to do this?
UPDATE:
the answer by #devnull worked very well, but now i have another problem, so i will refine my question a little:
i used the following command:
find /var/www -type d \( ! -wholename "/var/www/web-release-data/*" ! -wholename "/var/www/web-development-data/*" \)
the new problem that arises is that find for some reason is still traversing the whole directory tree of "/var/www/web-release-data/" and "/var/www/web-development-data/", thus it's very slow, and I fear it could take hours.
Is there any way make find completely exclude those directories and not traverse their respective directory hierarchies?
The following should work for you:
find A -type d \( ! -wholename "A/a/*" \)
This would list all subdirectories of A including A/a but excluding subdirectories of A/a.
Example:
$ mkdir -p A/{a..c}/{1..4}
$ find A -type d \( ! -wholename "A/a/*" \)
A
A/c
A/c/4
A/c/2
A/c/3
A/c/1
A/a
A/b
A/b/4
A/b/2
A/b/3
A/b/1
Another solution:
find A \! -path "A/a/*"
If you don't want a as well, use
find A \! -path "A/a/*" -a \! -path "A/a"
Have you tried rsync(1)? It has an option --exclude=PATTERN which might work well here:
rsync -avz --exclude=A/a <source> <target>
Using rsync you wouldn't need to use find(1)
To exclude 2 subdirs:
find . -type d ! -wholename "dir/name/*" -a ! -wholename "dir/name*"
To answer your updated question, you can do
find /var/www -wholename "/var/www/web-release-data/*" -o -wholename "/var/www/web-development-data/*" -prune -o -type d -print

Resources