Delete files older than certain days that not have certain substring in name (Linux) - linux

I have a folder with backup files with names like:
backup_2017_12_01__09_00_01.sql.gz
backup_2017_12_01__10_00_01.sql.gz
...
backup_2017_12_01__19_00_01.sql.gz
backup_2017_12_01__20_00_01.sql.gz
backup_2017_12_02__09_00_01.sql.gz
backup_2017_12_02__10_00_01.sql.gz
...
backup_2017_12_02__19_00_01.sql.gz
backup_2017_12_02__20_00_01.sql.gz
and so on.
I have a cron that should perform the deletion of the files respecting these rules:
delete all files older than 45 days; solved with find. -mtime +45 -exec rm {} \;
delete all files older than 7 days except those with the string __20_ in the name (the last backup in the evening); a command that is based on the last modification time rather than the name would also be fine
Can someone help me on the second point?
Thanks.

find /p/a/t/h \( -mtime +45 -o \( -mtime +5 ! -name '*__20_*' \) \) -delete
If you want, you can be more explicit:
find /p/a/t/h \( -mtime +45 -o \( -mtime +5 -and ! -name '*__20_*' \) \) -delete
Note that you should be more precise with language. This does not delete files that are "older than 45 days". It deletes files based on their modification time, which can be very different than age.

With find's -name test:
find . -type f -name "*.gz" ! -name "*__20_*.gz" -mtime +7 -delete

Related

How to exclude multiple subdirectories (same directory name) when using find command to delete files older than 30 days in a batch file?

Given the below linux directory structure, how would I skip each excluded directory, (/assess), to remove files older than 30 days for the rest of the entire directory structure?
Thanks for your assistance...
/mnt/nfsmountpoint/location1/appliance1
/assess
/discover
/bkup
/mnt/nfsmountpoint/location1/appliance2
/assess
/discover
/bkup
etc...
I cobbled together an answer and proofs:: (my asterisks * are not showing sorry)
Run from the /mnt/nfsmountpoint/ directory.
find .// -not -path "/assess/" -type f -mtime +30 -delete
validate::
Does it skip the directory?:
find .// -not -path "/assess/" -type f -mtime +30 -ls|more
Verify no current month (January 2021) files included?:
find .// -not -path "/assess/" -type f -mtime +30 -ls|grep Jan
How much space is made free?:
find .// -not -path "/assess/" -type f -mtime +30 -print0 | du --files0-from=- hc | tail -n1
find /path/to/dir -mtime +30 -type f -not -name "*assess*" -delete
Find files (-type f) in /path/to/dir as well as children directories. Specify only files that have been modified more than 30 days ago (-mtime +30) and do not include files that contain "assess" (-not -name "assess")

Delete files older than 30 days, but in 1 directory the retention 6 months

I'd like to create a find which delete a files older than 30 days, but I have 1 directory where the retention should be 6 months.
How would that be possible?
This one would delete all files in all subdirectories which is older than 30 days if I'm correct.
/bin/find /root/script/* -type f -ctime +30 -exec rm {} \;
Bu how I can set that this directory needs different retention:
/root/script/owner
You can exclude the /root/script/owner from the find output using -path or -regex, combined with '!' to negate the test
find /root/script -type f -ctime +30 '!' -path '/root/script/owner/*' -exec rm {} \;
OR
find /root/script -type f -ctime +30 '!' -regex '/root/script/owner/.*' -exec rm {} \;
Then execute the custom delete on the special folder
find /root/script/owner -type f -ctime +180 -exec rm {} \;
You can combine multiple operators so that they restrict what is included. You actually already do this because you have a -type and -ctime, joined with an implicit AND.
The one you need to add is regex, and you can do something like:
/bin/find /root/script/* -type f ! -regex '/root/script/owner/.*' -ctime +30 -exec rm {} \;
This should exclude files in that particular tree since the ! -regex will be false for them. The basic idea is that only those that pass all the conditions will be subject to further operations.
In this case, any non-regular files will be excluded. Of the others, any that don't match the regex will be excluded. Of those remaining ones, we'll throw away any that don't match the 30-day requirement. Whatever's left will be actioned by the rm.
The remaining directory, of course, is done with the greater time:
/bin/find /root/script/owner -type f -ctime +186 -exec rm {} \;

FInd patternf for multiple pattern of files

I need to search for multiple pattern of files and check their mtime and if it morethan 30 days then delete all the files. I am using the below command but it's deleting only one pattern of file and not all. Kindly let me know where is the mistake in my command.
find /root -type f \( -name "*.tgz" -o -name "*.bz2" \) -mtime +30 -print -exec rm '{}' +
Try escaping parentheses in the command and adding a wildcard character:
find /root -type f \( -name "*.tgz" -o -name "*.bz2" \) -mtime +30 -exec rm {} \+

Using "find … -delete" to remove image files only from special subdirectories

I need to clean up some subdirectories inside my music collection from unwanted images. I’m using Ubuntu 14.04 and/or Linux Mint 17.2 and a bash shell script using the find command.
The directory structure (minimal example) is as follows:
Tagged
Artist #1
Artist #1 - An Album
Artist #1 - A Track.flac
cover.jpg
something.png
Artist #1 - [compilations]
Artist #1 - A Track.flac
cover.jpg
something.png
Artist #2
Artist #2 - Another Album
Artist #2 - A Track.mp3
cover.jpg
Only in the subfolders ending with "[compilations]", I want to delete all kind of jpeg and/or png images (because the tagging software erroneously puts them there). Any images that happen to be in normal "album" folders I wish too keep.
With my directory structure, folders with "[compilations]" in the name can only happen just below the "Artist" folders, repectively; so a maximum of two levels deep.
I came up with the following find command:
$ cd Tagged
$ find . -maxdepth 2 -type d -name '*\[compilations\]' -exec find {} -type f -iname '*.jp*g' -or -iname '*.png' -delete \;
This seems to do something and takes a while, but the files "./Artist #1/Artist #1 - [compilations]/cover.jpg" and "./Artist #1/Artist #1 - [compilations]/something.png" are still there (and all other image files).
Being quite new to Linux, I assume I make a dumb mistake using find's -delete option, because the following command (without -delete) shows the files correctly:
$ find . -maxdepth 2 -type d -name '*\[compilations\]' -exec find {} -type f -iname '*.jp*g' -or -iname '*.png' \;
./Artist #1/Artist #1 - [compilations]/cover.jpg
./Artist #1/Artist #1 - [compilations]/something.png
So here are my questions:
Why does the -delete not work?
Is this command really safe regarding "extravaganza" like whitespace, glob characters and foreign characters in the paths and filenames?
How would I have to rewrite the above command, still using bash and find?
Could the command be optimized (re speed, safety, nested finds)?
In the actual collection, the command must traverse 16899 folders, almost all of them contain whitespace and foreign characters (like Czech, Russian, Japanese, Greek, German …), so it must be robust.
Thanks in advance for any insights and some enlightenment!
Your -delete predicate only applies to the
-iname '*.png'
predicate, because you missed groupings: when you give find the following:
-type f -iname '*.jp*g' -or -iname '*.png' -delete
because of the precedence of the boolean operators, find understands:
\( -type f -iname '*.jp*g' \) -or \( -iname '*.png' -delete \)
To fix this, use:
-type f \( -iname '*.jp*g' -or -iname '*.png' \) -delete
I'd suggest that to experiment you replace -delete with -print: you'll see what the -delete applies to!
Now, regarding your nested find: because of the structure of your directory tree (your files are only in depth 3), you should be able to do with only one instance of find:
find -maxdepth 3 -path '*/*\[compilations\]/*' \( -iname '*.jp*g' -o -iname '*.png' \) -type f -print
(I put -print instead of -delete so that you can check the command before executing it with -delete).
After some experimentation, I think my error was in not putting the OR'ed part in parentheses—it seems find used the -delete only on the right part of the last OR, i.e., tried to delete '*.png'. Alas, almost all of my cover images were '*.jpg' so I thought it wouldn't work at all!
So I think the corrected command should be:
$ find . -depth -maxdepth 2 -type d -name '*\[compilations\]' -exec find {} -type f \( -iname '*.jp*g' -or -iname '*.png' \) -delete \;
It seems to work correctly on my test case above.
Nevertheless, some confirmation would be nice. An maybe some answers to my other questions, just for information and learning. Thank you!

Linux: Delete every file older than a date with one exceptional file

I am able to delete lets say all regular files in a folder older than 7 days via:
find /path/to/dir -type f -mtime +7 -exec rm {} \;
with a single problem. There is a file here (.gitignore) which I want to keep. I tried using regex but apparently findutils regex does not have support for negative lookahead (?!gitignore)
Any other ideas?
Use ! -name .gitignore
find /path/to/dir ! -name .gitignore -type f -mtime +7 -exec rm {} \;
You can group multiple arguments within escaped parentheses. Example, to remove all files except .gitignore and javascript files (ending in .js):
find /path/to/dir ! \( -name ".gitignore" -o -name "*.js" \) -type f -mtime +7 -exec rm {} \;
-o means or

Resources