Exclude a sub-directory using find - bash

I have directory structure like this
data
|___
|
abc
|____incoming
def
|____incoming
|____processed
123
|___incoming
456
|___incoming
|___processed
There is an incoming sub-folder in all of the folders inside Data directory. I want to get all files from all the folders and sub-folders except the def/incoming and 456/incoming dirs.
I tried out with following command
find /home/feeds/data -type d \( -name 'def/incoming' -o -name '456/incoming' -o -name arkona \) -prune -o -name '*.*' -print
but it is not working as expected.
Ravi

This works:
find /home/feeds/data -type f -not -path "*def/incoming*" -not -path "*456/incoming*"
Explanation:
find /home/feeds/data: start finding recursively from specified path
-type f: find files only
-not -path "*def/incoming*": don't include anything with def/incoming as part of its path
-not -path "*456/incoming*": don't include anything with 456/incoming as part of its path

Just for the sake of documentation: You might have to dig deeper as there are many search'n'skip constellations (like I had to). It might turn out that prune is your friend while -not -path won't do what you expect.
So this is a valuable example of 15 find examples that exclude directories:
http://www.theunixschool.com/2012/07/find-command-15-examples-to-exclude.html
To link to the initial question, excluding finally worked for me like this:
find . -regex-type posix-extended -regex ".*def/incoming.*|.*456/incoming.*" -prune -o -print
Then, if you wish to find one file and still exclude pathes, just add | grep myFile.txt.
It may depend also on your find version. I see:
$ find -version
GNU find version 4.2.27
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION SELINUX

-name only matches the filename, not the whole path. You want to use -path instead, for the parts in which you are pruning the directories like def/incoming.

find $(INP_PATH} -type f -ls |grep -v "${INP_PATH}/.*/"

By following answer for How to exclude a directory in find . command:
find . \( -name ".git" -o -name "node_modules" \) -prune -o -print

This is what I did to exclude all the .git directories and passed it to -exec for greping something in the
find . -not -path '*/\.*' -type f -exec grep "pattern" [] \;
-not -path '*/\.*' will exclude all the hidden directories
-type f will only list type file and then you can pass that to -exec or whatever you want todo

Related

find and delete folder and/or zip file in a directory [duplicate]

I was trying to get a list of all python and html files in a directory with the command find Documents -name "*.{py,html}".
Then along came the man page:
Braces within the pattern (‘{}’) are not considered to be special (that is, find . -name 'foo{1,2}' matches a file named foo{1,2}, not the files foo1 and foo2.
As this is part of a pipe-chain, I'd like to be able to specify which extensions it matches at runtime (no hardcoding). If find just can't do it, a perl one-liner (or similar) would be fine.
Edit: The answer I eventually came up with include all sorts of crap, and is a bit long as well, so I posted it as an answer to the original itch I was trying to scratch. Feel free to hack that up if you have better solutions.
Use -o, which means "or":
find Documents \( -name "*.py" -o -name "*.html" \)
You'd need to build that command line programmatically, which isn't that easy.
Are you using bash (or Cygwin on Windows)? If you are, you should be able to do this:
ls **/*.py **/*.html
which might be easier to build programmatically.
Some editions of find, mostly on linux systems, possibly on others aswell support -regex and -regextype options, which finds files with names matching the regex.
for example
find . -regextype posix-egrep -regex ".*\.(py|html)$"
should do the trick in the above example.
However this is not a standard POSIX find function and is implementation dependent.
You could programmatically add more -name clauses, separated by -or:
find Documents \( -name "*.py" -or -name "*.html" \)
Or, go for a simple loop instead:
for F in Documents/*.{py,html}; do ...something with each '$F'... ; done
This will find all .c or .cpp files on linux
$ find . -name "*.c" -o -name "*.cpp"
You don't need the escaped parenthesis unless you are doing some additional mods. Here from the man page they are saying if the pattern matches, print it. Perhaps they are trying to control printing. In this case the -print acts as a conditional and becomes an "AND'd" conditional. It will prevent any .c files from being printed.
$ find . -name "*.c" -o -name "*.cpp" -print
But if you do like the original answer you can control the printing. This will find all .c files as well.
$ find . \( -name "*.c" -o -name "*.cpp" \) -print
One last example for all c/c++ source files
$ find . \( -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" \) -print
I had a similar need. This worked for me:
find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print
My default has been:
find -type f | egrep -i "*.java|*.css|*.cs|*.sql"
Like the less process intencive find execution by Brendan Long and Stephan202 et al.:
find Documents \( -name "*.py" -or -name "*.html" \)
Braces within the pattern \(\) is required for name pattern with or
find Documents -type f \( -name "*.py" -or -name "*.html" \)
While for the name pattern with and operator it is not required
find Documents -type f ! -name "*.py" -and ! -name "*.html"
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done
simple but works :)
I needed to remove all files in child dirs except for some files. The following worked for me (three patterns specified):
find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +
This works on AIX korn shell.
find *.cbl *.dms -prune -type f -mtime -1
This is looking for *.cbl or *.dms which are 1 day old, in current directory only, skipping the sub-directories.
find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"
What about
ls {*.py,*.html}
It lists out all the files ending with .py or .html in their filenames

Excluding multiple filetypes with find

I have a folder with 20k plus Images and most gui filemanagers (like dolphin) aren't able to manage this amount of data.
So I decided to use the bash instead. My problem is the following:
most of the files are *.IMG or *.LBL files
I am not interested in those files. I look for the others
with find . -type f -not -name "*.LBL" I am able to see all files instead of the *.LBL
with find . -type f -not -name "*.IMG" I am able to see all files instead of the *.IMG
both is not very helpful, since it still fills my terminal
either combining both seems not to work:
find . -type f -not -name "*.LBL" -o -not -name "*.IMG"
What is the correct way to see the files inside a folder excluding multiple filesuffixes?
Group conditions, I think -o -not isn't working as expected. Try this:
find . -type f -not \( -name "*.LBL" -o -name "*.IMG" \)
You can use bash's extended pattern matching (Might have to be turned on in a script with shopt -s extglob; usually enabled by default in an interactive shell):
printf "%s\n" !(*.LBL|*.IMG)

find how to exclude path

I want to find all files in /usr/ but not in /usr/share
from this post Exclude a sub-directory using find
I tried:
find /usr -type f -not -path /usr/share -print
-> print files from /usr/share
from this post How to exclude a directory in find . command
I tried:
find /usr -path /usr/share -prune -print
->outputs nothing altough there are files in /usr/bin
I also tried:
find /usr -path ! /usr/share -type f -print
-> outputs an error
Drop -print and negate -path ... -prune:
find /usr ! \( -path '/usr/share' -prune \) -type f
By default, a boolean and is used to join operators and primaries. So find /usr -path /usr/share -prune -print is equvialent to find /usr -path /usr/share -prune -a -print. But you want to print things that are not pruned. So use:
find /usr -path /usr/share -prune -o -print
If you want to limit the search to regular files:
find /usr -path /usr/share -prune -o -type f -print

Bash delete all folders except some

I have a directory with this structure:
main/
Antispam/res/values/
strings.xml
plurarls.xml
arrays.xml
Backup/res/values/
strings.xml
plurarls.xml
arrays.xml
etc.
Antispam and Backup have other folders inside, but I do not need those. I just want to have only the values folder with the three XML files (strings.xml, plurarls.xml and arrays.xml). How can I do that?
if you run this in the parent directory:
find . -regex '.*backup.*'
you would have something like this:
./backup
./backup/res
./backup/res/value
./backup/res/value/00.xml
./backup/res/value/02.xml
./backup/res/value/01.xml
And then you can invert the match by -not
find . -not -regex '.*backup.*'
and of course you can make it more specific with -type d and literal ./
find . -type d -not -regex './backup.*'
and then do any thing you like with the output
This is what I would do. Basically just find folders excluding the parent folders and send them to oblivion.
find main/Antispam/res/values/ '!' -path main/Antispam/res/values/ -type d | xargs rm -f -r $1
find main/Backup/res/values '!' -path main/Backup/res/values -type d | xargs rm -f -r $1
Hope it works for you! :)
This work for me:
ale8530#vmi81507:~/Scrivania/APK-Tools-Linux-master/working$ find . -regex '.*res/values/strings.*'
./WaliLive/res/values/strings.xml ./SystemAdSolution/res/values/strings.xml ./SampleExtAuthService/res/values/strings.xml ./DocumentsUI/res/values/strings.xml ./CaptivePortalLogin/res/values/strings.xml ./SoundRecorder/res/values/strings.xml ./ExternalStorageProvider/res/values/strings.xml ./MiuiCompass/res/values/strings.xml ./CloudBackup/res/values/strings.xml ./BackupRestoreConfirmation/res/values/strings.xml ./AntHalService/res/values/strings.xml ./MiuiSuperMarket/res/values/strings.xml ./DownloadProvider/res/values/strings.xml ./VpnDialogs/res/values/strings.xml ./XiaomiAccount/res/values/strings.xml ./SpacesCore/res/values/strings.xml ./CdmaCallOptions/res/values/strings.xml
Can you copy this output to another director
y? Keeping the same output?
For example
From-->./WaliLive/res/values/strings.xml to ./WaliLive.apk/res/values/strings.xml
Thanks
PLEASE BACKUP YOU DATA BEFORE YOU TRY!!!
if you don't care about empty dirs (or you don't care to do everything with one command), i'll do something like:
find ! -name strings.xml ! -name plurarls.xml ! -name arrays.xml -type f -delete
if you care about empty dirs:
find -type d -print0 | xargs -0 rmdir -p

Or condition in bash pattern

I'm searching some files with: find . -name "*.en.php" and find . -name "*.fr.php".
I want both commands in the same line, something like : find . -name "*.(en|fr).php" but it doesn't work.
Thanks in advance for your help.
EDIT
my command is like this : find . -not -path Config -name "*.fr.php", is there a solution do not repeat -not -path Config ?
Try:
find -name "*.en.php" -o -name "*.fr.php"
If you for example want to run command on each found file, than you need to additional ()
(this will count num of lines in all found files):
find \( -name "*.en.php" -o . -name "*.fr.php" \) -exec cat {} \; | wc -l
You should be able to combine expression with an or operator, thus:
find . -name '*.en.php' -o -name '*.fr.php' ...
You can see all the operators in the man page listed under OPERATORS (and, or, not, parentheses and so forth).
Use the find -o operator, eg.
find . -name "*.en.php" -o -name "*.fr.php"
Edit:
Like so:
find . -path './Config' -prune -o \( -name "*.en.php" -o -name "*.fr.php" \)
The default operator in find (if one is ommited) is and, the parentheses group the name expression. I've added -prune to prevent find from recursing into the Config directory.

Resources