LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.

Notices


Reply
  Search this Thread
Old 04-04-2018, 04:09 PM   #1
dazzpowder
LQ Newbie
 
Registered: Nov 2015
Posts: 19

Rep: Reputation: Disabled
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
 
Old 04-04-2018, 06:19 PM   #2
scasey
LQ Veteran
 
Registered: Feb 2013
Location: Tucson, AZ, USA
Distribution: CentOS 7.9.2009
Posts: 5,708

Rep: Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210
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.
 
1 members found this post helpful.
Old 04-04-2018, 06:59 PM   #3
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,103

Rep: Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117
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.
 
Old 04-05-2018, 12:50 AM   #4
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,768

Rep: Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193
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)!
 
Old 04-05-2018, 08:27 AM   #5
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,770

Rep: Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210
Quote:
Originally Posted by syg00 View Post
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

Last edited by rknichols; 04-05-2018 at 08:40 AM.
 
1 members found this post helpful.
Old 04-05-2018, 08:31 AM   #6
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,103

Rep: Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117
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.
 
Old 04-05-2018, 08:38 AM   #7
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,770

Rep: Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210
Quote:
Originally Posted by syg00 View Post
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.

Last edited by rknichols; 04-05-2018 at 08:41 AM.
 
Old 04-05-2018, 08:42 AM   #8
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,103

Rep: Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117Reputation: 4117
lol - stoppit ....
 
Old 04-05-2018, 09:01 AM   #9
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,768

Rep: Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193
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.
 
Old 04-05-2018, 03:35 PM   #10
dazzpowder
LQ Newbie
 
Registered: Nov 2015
Posts: 19

Original Poster
Rep: Reputation: Disabled
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?
 
Old 04-05-2018, 04:18 PM   #11
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,768

Rep: Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193
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

Last edited by MadeInGermany; 04-05-2018 at 04:41 PM. Reason: --file-type puts directory/, a while loop retains spaces in filenames
 
Old 04-05-2018, 05:41 PM   #12
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,770

Rep: Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210
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.

Last edited by rknichols; 04-05-2018 at 05:57 PM. Reason: I should add that ...
 
1 members found this post helpful.
Old 04-05-2018, 06:08 PM   #13
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,768

Rep: Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193Reputation: 1193
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
 
Old 04-05-2018, 08:33 PM   #14
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,770

Rep: Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210Reputation: 2210
Quote:
Originally Posted by MadeInGermany View Post
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.
 
Old 04-06-2018, 02:10 PM   #15
dazzpowder
LQ Newbie
 
Registered: Nov 2015
Posts: 19

Original Poster
Rep: Reputation: Disabled
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!
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How to exclude a sub directory within a directory and process the files alone newuser85 Linux - Newbie 5 11-03-2015 06:23 AM
Using Find with an exclude/exclude file metallica1973 Linux - General 8 11-06-2011 09:39 PM
exclude directory with cp hampel Linux - Software 3 06-04-2009 11:59 AM
Mod_rewrite exclude directory Albin Joseph Linux - Server 1 10-22-2007 04:51 AM
exclude directory from find ebasi Linux - Software 8 07-17-2004 02:12 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - General

All times are GMT -5. The time now is 02:42 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration