Purge multiple file types

How can I quickly, but safely, purge old *.txt, *.log, *.tmp files from a directory.  I have this alias defined in my .bash_profile file.  It is very handy, but I realize that it is dangerous:

alias purge_30='find . -name '\''*.*'\'' -mtime +30 -exec rm {} \;'

That will quickly delete *ALL* files in my current directory that are more than 30 days old.  I intend to use this only in directories that contain log or temp files.  But, if I accidentally run this in a directory with executable files for example, that could quickly create a big problem!

Here is what I think I want in pseudo-code:  (I don't know how to write the "or" condition to include multiple extensions.)

Find all files with extensions of *.txt or *.log, or *.tmp that are more than 30 days old and delete them.

If the command could exclude any executable files that would be nice.  If the command could also accept an optional different value for the number of days, that would be nice too.
LVL 36
Mark GeerlingsDatabase AdministratorAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

farzanjCommented:
find . \(-name '*txt' -o -name '*log' or -name '*tmp' \) -mtime +30 !-executable -exec rm {} \;'

Open in new window



or

find ./ -regex ".*\.\(tmp\|log\|txt\)"  ! -executable | xargs rm -f 

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Mark GeerlingsDatabase AdministratorAuthor Commented:
When I try your first suggestion, as I was hoping to use it (inside an alias that I create) I get:
find: invalid predicate `(-name'

I created that alias like this:
alias purge_test='find . \(-name '*txt' -o -name '*log' or -name '*tmp' \) -mtime +30 !-executable -exec ls -l {} \;'

I wanted to test it with "ls -l" before running the "rm".  Or, is the "ls -l" possibly the problem?

When I try your first command directly (not via an alias) I get this error:
-bash: !-executable: event not found

Your second command does not include any check of dates, and when I add "-mtime +30", that seems to ignored.  (I changed that to "xargs ls -l" instead of "xargs rm -f" to try to confirm that it would find just the files I want it to find.)  I'm doing my testing in a test system, but still if an "rm" command runs without the limits I expect, it may delete some recent files that I would prefer to save.
0
farzanjCommented:
Sorry my bad.  You need a space.
! -executable  <-- space between ! and -executable


Also space
\( -name

Instead of
\(-name

It is a lot faster using pipe xargs instead of -exec option of the find command.  I just presented another thing to think about.
0
Newly released Acronis True Image 2019

In announcing the release of the 15th Anniversary Edition of Acronis True Image 2019, the company revealed that its artificial intelligence-based anti-ransomware technology – stopped more than 200,000 ransomware attacks on 150,000 customers last year.

Mark GeerlingsDatabase AdministratorAuthor Commented:
OK, that's closer on the first one.  Now it gives me this error:
find: paths must precede expression

And, I had tried:
find . \( -name '*txt' -o -name '*log' or -name '*tmp' \) -mtime +30 ! -executable -exec ls -l {} \;

I admit that I am certainly no master of shell scripting syntax.  To me it looks like the path (the ".'" character, correct?) does preceed the expressions (-time, -executable, etc.) so why does Linux complain?

I believe you that your second option using xargs is faster, but how can I include the check of the age of the file?  I don't want to delete all *.log files, just those that are older than a value I can set (30 days in this case).
0
ThomasMcA2Commented:
Your "or" needs a dash in front of it. You can use "-o" or "-or" but not "or".
0
farzanjCommented:
Thank you.  Yes, I used -o and or was just typo.
0
skullnobrainsCommented:
you probably forgot to escape something while creating the alias

here is a similar working example (notice i'm using simple quotes and a single escape char wherever needed)

$ alias tst='find . \( -name \*x\* -or -name \*y\* \) \! -executable'

Open in new window


resulting in

$ alias tst
alias tst='find . \( -name \*x\* -or -name \*y\* \) \! -executable'

Open in new window


notice the backslashes before * ( ) ! are still there

the alias does work as expected

$ mkdir xx
$ cd xx
$ touch fxfege hklynkllk jkk nkk njnlkn dddx
$ tst
./hklynkllk
./dddx
./fxfege

Open in new window


if you can't figure it out, you probably had better copy-paste the command you use to create the alias, the one you type when you test it and the results
0
ThomasMcA2Commented:
Thank you.  Yes, I used -o and or was just typo.

When I copied and pasted your line into my terminal, then added a dash, it worked. So, to help determine if the problem is a syntax issue or the alias, try running the command manually until you get the syntax right. Once that works, convert it to an alias.
0
Mark GeerlingsDatabase AdministratorAuthor Commented:
When I try this:
find . \( -name \*x\* -or -name \*y\* \) \! -executable

I get:
find: invalid predicate `-executable'

I would expect to need something beyond the "-executable" in that example.  I would expect to see something like "-exec..." or maybe | xargs ...

To review, this is what I have working currently:

alias purge_30='find . -name '\''*.*'\'' -mtime +30 -exec rm {} \;'

(Those are all single quotes.)

That works with no errors.  But it is dangerous.  I'm just trying to get a test for a few common file extensions (*.txt, *.log, *.tmp, etc.) instead of the wide-open *.*.  Is that not possible in a Bash shell script in Linux?

IF you think you have something that works, can it be tested with "ls -l" instead of "rm"?
0
skullnobrainsCommented:
if your find version does not support "-executable", it should support "-perm 110". you need to refer to your man page

you can test easily by adding echo in front of rm. find will print the exact commands it would execute. you can also remove -exec and everything that follows in order to see what find will match while you fiddle with the command
0
Mark GeerlingsDatabase AdministratorAuthor Commented:
"you need to refer to your man page"

That's not what I was hoping to hear!  I find the "man" pages in Linux to be extremely disappointing.  Their lack of some common, useful examples is their biggest weakness in my opinion.  Sure, it is a little bit helpful to see every possible option variation for a command documented.  But, without any clues as to when or why one particular option might be chosen over another one, I find the brief explanations in the "man" pages to be not very helpful most of the time.

This almost works for me:

alias purge_30='find . -name \*.log -o -name \*.txt -mtime +30 -exec ls -lt {} \;'

I say "almost works" because it at least doesn't give me an error.  But, it uses only the extension that was specified last (*.txt) in this case.  If I reverse those, and put *.txt first on the line, then *.log last, it finds only the *.log files.

If I try to include "(" and ")" around the -o, I get:
bash: syntax error near unexpected token `('
0
ThomasMcA2Commented:
Did you use "(" or "\("? The backslash in front of each paren is necessary.

You need to look at the man page to find the syntax that works for your shell. If you are unwilling to do that, then we can only provide answers that almost work.
0
Mark GeerlingsDatabase AdministratorAuthor Commented:
Thank you for your help.  This is what I ended up with:

alias purge_30='find . -maxdepth 1 -type f \( -name \*.txt -o -name \*.log -o -name \*.tmp -o -name \*.bak -o -name \*.tr\? \) -mtime +30 -exec rm {} \;'

And no, I don't see anything in the "man" page for "find" about needing parenthesis around the "or" conditions, or that the escape (backslash) character is required before a parenthesis.  Maybe these are details that UNIX/Linux experts or shell script experts just know?  (I may be an Oracle expert, but I'm not an expert in those two categories.)
0
skullnobrainsCommented:
if you want exact answers, you need to provide the exact os version. there are tiny differences such as the -executable predicate which is present in some find versions but not all. there is no way we can guess.

the man page specifies the order between "-and" and "-or" and the fact that "-and" is implicit, but it's true that the man page for find is pretty long and is easier to use for reference once you're used to the command than in order to figure things out in the first place

the requirement for escaping the parenthesis is not related to the find syntax. the shell would interpret the parenthesis otherwise, hence the error message you had earlier

regards
0
Mark GeerlingsDatabase AdministratorAuthor Commented:
Thank you.  I realized right after I had accepted the other responses that I hadn't given you any of the points.  I'm sorry about that, I had intended to, becasue your responses were also informative.

Basically, I try to avoid doing much in Linux directly, because I have no UNIX experience, and not a lot of Linux experience either.  I liked the DEC VAX o/s back in the 90s and I have a lot of experience with the DOS/Windows command line.  But, I've never had the luxury of working alongside of someone who knows Bash shell scripting or Linux well.  I try to stay in my Oracle world, but every Oracle database needs an o/s of some kind, and some tasks are easier and/or more efficient in the o/s than in the database.
0
skullnobrainsCommented:
no problem, i'm not fishing for points but i appreciate your concern.

if you have experience with dos shell, you'll probably find out that sh-type shell scripting is not that hard to self-teach, much more similar to a regular programming language and impressively powerful. it's pretty useful for an oracle admin to know a little shell and how to shedule jobs and rather os-agnostic except for windows
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Linux

From novice to tech pro — start learning today.