I'm trying to run a find
command for all JavaScript files, but how do I exclude a specific directory?
Here is the find
code we're using.
for file in $(find . -name '*.js')
do
java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done
This works because
find
TESTS the files for the pattern "*foo*":but it does NOT work if you don't use a pattern (
find
does not TEST the file). Sofind
makes no use of its former evaluated "true" & "false" bools. Example for not working use case with above notation:There is no
find
TESTING! So if you need to find files without any pattern matching use the -prune. Also, by the use of prunefind
is always faster while it really skips that directories instead of matching it or better not matching it. So in that case use something like:or:
Regards
For FreeBSD users:
There are lots of answers here already; I'm reluctant to add another, but I think that this information is useful.
TLDR: understand your root directories and tailor your search from there, using the "
-prune
" option.Background: I have a
rsnapshot
(rsync
) backup location,/mnt/Backups/
, that causes headaches when searching for system (/
) files, as those backups comprise ~ 4.5TB (terra) of files!I also have
/mnt/Vancouver
, my main working folder with TB of files, that is backed up [/mnt/Backups/
and/mnt/Vancouver/
are physically (redundantly) mounted on separate drives].Of the two top answers here (How to exclude a directory in find . command), I find that searching system files using the accepted answer is much faster, with caveats.
THIS one
finds that file in ~3-4 seconds; this one
appears (?) to recurse through all of the excluded directories (deeply nested
rsync
snapshots of all mounted volumes), so it takes forever. I'm presuming that it is searching multi-TB of files, so it's bogged down, interminably. For example, if I attempt to "time" that search (time find ...
), I see copious output -- suggesting thatfind
is deeply traversing the "excluded" directory:Appending a forward slash after the excluded directory (
/mnt/
) or a nested path (`/mnt/Backups') results in that search again* taking forever:Slow:
"SOLUTION"
Here are the best solutions (all of these execute in seconds). Again, my directory structure is
/
: root/mnt/Backups/
: multi-TB backups/mnt/Vancouver/
: multi-TB working directory (backed up to/mnt/Backups
on separate drive), which I often want to search/home/*
: other mountpoints/working "drives" (e.g./home/victoria
=~
)System files (
/
):To quickly find a system file, exclude
/mnt
(not/mnt/
or/mnt/Backups
, ...):which finds that file in ~3-4 seconds.
Non-system files:
E.g. to quickly locate a file in one of my two working "drives",
/mnt/Vancouver/
and/or/home/victoria/
).Backups:
E.g. to find a deleted file, in one of my hourly/daily/weekly/monthly backups).
Aside: Adding -print at the end of the command suppresses the printout of the excluded directory:
This is suitable for me on a Mac:
It will exclude
vendor
andapp/cache
dir for search name which suffixed withphp
.If search directories has pattern (in my case most of the times); you can simply do it like below:
In above example; it searches in all the sub-directories starting with "n".
There is clearly some confusion here as to what the preferred syntax for skipping a directory should be.
GNU Opinion
From the GNU find man page
Reasoning
-prune
stopsfind
from descending into a directory. Just specifying-not -path
will still descend into the skipped directory, but-not -path
will be false wheneverfind
tests each file.Issues with
-prune
-prune
does what it's intended to, but are still some things you have to take care of when using it.find
prints the pruned directory.-prune
only works with-print
and no other actions.-prune
works with any action except-delete
. Why doesn't it work with delete? For-delete
to work, find needs to traverse the directory in DFS order, since-delete
will first delete the leaves, then the parents of the leaves, etc... But for specifying-prune
to make sense,find
needs to hit a directory and stop descending it, which clearly makes no sense with-depth
or-delete
on.Performance
I set up a simple test of the three top upvoted answers on this question (replaced
-print
with-exec bash -c 'echo $0' {} \;
to show another action example). Results are belowConclusion
Both f10bit's syntax and Daniel C. Sobral's syntax took 10-25ms to run on average. GetFree's syntax, which doesn't use
-prune
, took 865ms. So, yes this is a rather extreme example, but if you care about run time and are doing anything remotely intensive you should use-prune
.Note Daniel C. Sobral's syntax performed the better of the two
-prune
syntaxes; but, I strongly suspect this is the result of some caching as switching the order in which the two ran resulted in the opposite result, while the non-prune version was always slowest.Test Script