I'm creating a cron that cleans subdirectories (first child only) of a specified folder of all but the most recent two files but running into issues.
These are my attempts:
find ./ -type d -exec rm -f $(ls -1t ./ | tail -n +4);
find . -maxdepth 2 -type f -printf '%T@ %p\0' | sort -r -z -n | awk 'BEGIN { RS="\0"; ORS="\0"; FS="" } NR > 5 { sub("^[0-9]*(.[0-9]*)? ", ""); print }' | xargs -0 rm -f
I also tried to create an array of files with the intention of going through the total minus 2, but the array was not populating with all files:
while read -rd ''; do x+=("${REPLY#* }"); done < <(find . -maxdepth 2 -printf '%T@ %p\0' | sort -r -z -n )
Could someone please give me a hand and explain how they have done?
Unlike the existing answer, this one NUL-delimits the output from find, and is thus safe for filenames with absolutely any legal character -- a set which includes newlines:
delete_all_but_last() {
local count=$1
local dir=${2:-.}
[[ $dir = -* ]] && dir=./$dir
while IFS='' read -r -d '' entry; do
if ((--count < 0)); then
filename=${entry#*$'\t'}
rm -- "$filename"
fi
done < <(find "$dir" \
-mindepth 1 \
-maxdepth 1 \
-type f \
-printf '%T@\t%P\0' \
| sort -rnz)
}
# example uses:
delete_all_but_last 5
delete_all_but_last 10 /tmp
Note that it requires GNU find and GNU sort. (The existing answer also requires GNU find).
This lists all but the most recent two files:
find -type f -printf '%T@ %P\n' | sort -n | cut -d' ' -f2- | head -n -2
Explanation:
-type f
list only files
-printf '%C@ %P\n'
%T@
show file's last modification time in seconds since 1970.
%P
show the file name
| sort -n
do a numeric sort
| cut -d' ' -f2-
drop the seconds form output, leave only the filename
| head -n -2
show all but the last two lines
So to remove all these files just append pipe it through xargs rm
or xargs rm -f
:
find -type f -printf '%T@ %P\n' | sort -n | cut -d' ' -f2- | head -n -2 | xargs rm
I just hit the same problem and that's how I solved it:
#!/bin/bash
# you need to give full path to directory in which you have subdirectories
dir=`find ~/zzz/ -mindepth 1 -maxdepth 1 -type d`
for x in $dir; do
cd $x
ls -t |tail -n +3 | xargs rm --
done
Explanation:
- with tail -n +number you decide how many files you leave in subdirectories