Delete files in a directory older than 7 days, but always leave at least 20 files intact
Solution 1
So we want to get the (regular) files that have mtime
more than 7 days ago AND are not within the 20 newest files.
One way to do that is to construct a list of files along with their modification times and a flag indicating whether the file is mtime +7
or not. We can then sort the list by mtime
, and take all but the 20 most recent1. Finally, iterate over the resulting list and delete only those that meet the age threshold:
find ./recentpicturesdirectory -type f \( -mtime +7 -printf 'Y\t' -o -printf 'N\t' \) -printf '%A@\t%p\0' |
sort -zk2,2 | head -zn -20 | while read -r -d '' flag _ file; do \
case "$flag" in
'Y') echo rm "$file"
;;
*) echo "skipping $file (too new)"
;;
esac
done
By using \0
termination and adding the -z
flag to the sort
and head
(or tail
) commands, we can handle any legal filenames without choking on whitespace.
The echo
is added for testing purposes; remove it once you're certain that the desired files are selected for deletion.
1 If we sort in ascending order of mtime (i.e. old to new), we can use head -n -20
to select all but the last 20; alternatively we could sort in descending order of mtime (new to old) and use tail -n +21
If you have zsh
, then you can do it all with glob qualifiers, I think:
rm ./recentpicturesdirectory/**/*(.^om[1,20]^m+7)
where
**/*
matches recursively (equivalent of bashglobstar
)(.)
match regular files onlyom[1,20]
lists results in ascending order of mtime, and select the first 20m+7
match only files withmtime
> 7 days^
invert everything that follows
so the logic is
regular files NOT (in 20 most recent by mtime OR NOT mtime +7 days)
which (by application of de Morgan's rules) is equivalent to
regular files (NOT in 20 most recent by mtime) AND (mtime +7 days)
Please do a trial run first though e.g.
print -rl ./recentpicturesdirectory/**/*(.^om[1,20]^m+7)
Solution 2
Here is a simple script to do this:
#!/bin/bash
IMGSPATH="/path/to/somewhere"
# count of all files within your directory
count=$(find $IMGSPATH -type f | wc -l)
# remove the ones older than of 7 days
while [ "$count" -gt "20" ]
do
find $IMGSPATH -type f -mtime +7 -print -delete -quit
count=$((--count))
done
- First we count all files within your desired directory.
- While the number of files within that directory is greater than of "20", then do:
- Find the first file older than of "7" days.
- Remove it
- Decrease the count of available files
- Do "#2" again ...
To test it:
mkdir /tmp/lab
cd /lab
touch {1..40}
touch -d "10 days ago" {1..20}
Save the script and run it for /tmp/lab
now files 1 to 20 should be deleted, run:
touch -d "10 days ago" {21..35}
run the script again, nothing will get removed cause you don't have more than of 20 files whatever they're old or not.
Related videos on Youtube
Dominik Meyer
Updated on September 18, 2022Comments
-
Dominik Meyer over 1 year
Beginner here: I want to sync pictures to a folder but want them to be recent. That's why I want them to be deleted if they are older then 7 days.
Current code for it:
find ./recentpicturesdirectory -mtime -7 -type f -delete
Now I need an exception because there should always be a minimum of 20 pictures in the folder.
I did some research but can't figure it out. Maybe use something else then the find command?
First sad try (told you I'm a beginner)
SIZE=find recentpictesfolder -type f | wc -l find ./recentpicturesdirectory -mtime -7 -type f \(-iname ".*" ! **if files part of -> .. i dont know ...**$SIZE ) -delete