LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   find exclude directory (https://www.linuxquestions.org/questions/linux-general-1/find-exclude-directory-4175627014/)

dazzpowder 04-04-2018 04:09 PM

find exclude directory
 
Hi All,

I have a small script which using the find command will delete certain files with in a given path. All works but now I need to exclude a directory or directories but cant seem to get it to work can anyone help?

This is the one line that does the delete

find $path -type f \( -iname \*.csv -o -iname \*.xml -o -iname \*.zip -o -iname \*.gz \) -mtime $olderthan -delete

scasey 04-04-2018 06:19 PM

I think you want -path with -prune
From man find:
Code:

      -path pattern
              File name matches shell pattern pattern.  The metacharacters do not treat `/' or `.' specially; so, for example,
                        find . -path "./sr*sc"
              will  print  an  entry  for  a directory called `./src/misc' (if one exists).  To ignore a whole directory tree, use -prune rather than checking every file in the tree.  For example, to skip the
              directory `src/emacs' and all files and directories under it, and print the names of the other files found, do something like this:
                        find . -path ./src/emacs -prune -o -print
              Note that the pattern match test applies to the whole file name, starting from one of the start points named on the command line.  It would only make sense to use an absolute path name  here  if
              the relevant start point is also an absolute path.  This means that this command will never match anything:
                        find bar -path /foo/bar/myfile -print

Presumably, you can specify a non-match in the pattern, i.e.:
Code:

-path ./some/directory* -prune
but I've not tested that. Suggest careful reading of man find...there's LOTS to learn there.

syg00 04-04-2018 06:59 PM

Classic use case for prune - but then you can't use -delete.
Pipe it to xargs for rm. This also allows you to use echo first to test the list you generate - a very prudent step IMHO.

MadeInGermany 04-05-2018 12:50 AM

Good point, but simple xargs creates a problem (and even a risk) if there are space characters in file mames.
Rather than
-print0 | xargs -0 rm
I suggest to do everything in find
-exec rm {} +

Have the -prune first and continue with -o (otherwise)!

rknichols 04-05-2018 08:27 AM

Quote:

Originally Posted by syg00 (Post 5839483)
Classic use case for prune - but then you can't use -delete.

Why not?
Code:

find $path -name some_directory -prune -o \
    -type f \( -iname \*.csv -o -iname \*.xml -o -iname \*.zip -o -iname \*.gz \) -mtime $olderthan -delete

Either the "-prune" term OR the "-delete" term will be executed, never both.

If multiple directories need to be pruned, then:
Code:

find $path \( -name dir1 -o -name dir2 -o -name dir3 \) -prune -o \
    -type f \( -iname \*.csv -o -iname \*.xml -o -iname \*.zip -o -iname \*.gz \) -mtime $olderthan -delete

Here's an alternate syntax that directly expresses that the "-delete" term will not be executed for the pruned directories:
Code:

find $path ! \( \( -name dir1 -o -name dir2 -o -name dir3 \) -prune \) \
    -type f \( -iname \*.csv -o -iname \*.xml -o -iname \*.zip -o -iname \*.gz \) -mtime $olderthan -delete


syg00 04-05-2018 08:31 AM

Quote:

Originally Posted by find_manpage
Because -delete implies -depth, you cannot usefully use -prune and -delete together.

me, I just do as I'm told.

rknichols 04-05-2018 08:38 AM

Quote:

Originally Posted by syg00 (Post 5839658)
Quote:

Originally Posted by find_manpage
Because -delete implies -depth, you cannot usefully use -prune and -delete together.
me, I just do as I'm told.

Arrrgh! Forgot about that (obviously). find will descend into the directory before doing the prune.

syg00 04-05-2018 08:42 AM

lol - stoppit ....

MadeInGermany 04-05-2018 09:01 AM

IMHO a questionable feature
 
GNU find's "The -delete action automatically turns on -depth" is a bad idea IMHO.
It still could delete files (and maybe even empty directories), and otherwise would silently fail.

dazzpowder 04-05-2018 03:35 PM

Thanks All for the help. prune seems to have done the job.

Is there a way to record to a log the files that are about to be deleted with their creation date? If I use the -print option, only the processed files are recorded, I could use the find and ls command before the find and delete something like -exec ls -ltr {} + | awk '{print $6,$7,$8,$9}' > $log but this doubles the time it takes to run the script. -print was perfect as it does it all in one go and there is no discrepancy with what was deleted and logged, But having the creation date along with the file name would be ideal as the script works out the older than date so anyone can browse the list to ensure that no files later than the 'older than date' have been deleted.

Any ideas?

MadeInGermany 04-05-2018 04:18 PM

You can have -exec ls ... and -exec rm ... in sequence
Code:

find ... -exec ls -ldUo --file-type --time-style='+%Y-%m-%d %H:%M' {} + -exec rm -f {} + |
  while read -r x x x x line; do echo "$line"; done > $log


rknichols 04-05-2018 05:41 PM

You can use "-printf '%t %p\n'", which also accepts a very complete list of format directives if you want other information or specific formatting for the timestamp.

Note that none of these suggestions is going to give you "creation time". The best you can do is "modification time". Some filesystems do support "creation time", but support for that is lacking in the tools.

I should add that the disadvantage of using "-printf ..." is that the output is not sorted. The order will be that in which the files were found, and for many filesystems that is essentially unpredictable.

MadeInGermany 04-05-2018 06:08 PM

Nice! So it boils down to something like
Code:

find $path -path $excludepath -prune -o -type f \( -iname \*.csv -o -iname \*.xml -o -iname \*.zip -o -iname \*.gz \) -mtime $olderthan -printf "%TY-%Tm-%Td %TH:%TM %p\n" -exec rm -f {} + > $log

rknichols 04-05-2018 08:33 PM

Quote:

Originally Posted by MadeInGermany (Post 5839825)
Nice! So it boils down to something like
Code:

find $path -path $excludepath -prune -o -type f \( -iname \*.csv -o -iname \*.xml -o -iname \*.zip -o -iname \*.gz \) -mtime $olderthan -printf "%TY-%Tm-%Td %TH:%TM %p\n" -exec rm -f {} + > $log

As long as $excludepath is just a single directory (and with no embedded spaces in the name -- you really shold quote variables just to be safe) it looks good to me, though my reputation is somewhat tarnished in this thread. I'd certainly try it without the "-exec rm -f {} +" first, just to see what it would find.

dazzpowder 04-06-2018 02:10 PM

Thanks all for taking time out to help a newb. I read about printf in the man page but it didn't make much sense. It all works a treat - Thanks!


All times are GMT -5. The time now is 04:09 AM.