Bash: The JMRemover
This article explains how to use the find command to enumerate the number of files or folders in a directory, and how to delete old backup files or directories using the same technique.
This is an article in the category of dumping my internal wiki to this blog. This technique is inspired by the work of one of my colleagues.
Counting
To get the number of files or folder in a directory, the find command can be used, piped by wc.
Number of Files
nFiles=$(find $directory -maxdepth 1 -type f | wc -l)
- -maxdepth: ignore sub-directories
Number of Directories
nSubDirectories=$(find $directory -mindepth 1 -maxdepth 1 -type d | wc -l)
- -mindepth: ignore the base directory
- -maxdepth: ignore sub-directories
Remove old Files
This crazy one-liner, communicated to me by JMR, removes old files in a given directory:
find $directory -type f -iname '*.bak' -printf '%T@\t%p\0' | sort --zero-terminated --numeric-sort --reverse | tail --zero-terminated --lines=$((numberOfBackups-maxNumberOfBackups>=0 ? numberOfBackups-maxNumberOfBackups : 0)) | xargs --null --no-run-if-empty --max-args=1 echo | cut --fields=2 | xargs --no-run-if-empty rm --verbose
In English:
- find: find all .bak files in the directory
- printf: print two columns (date, filename) delimited by \0
- sort: sort files by date; --reverse means that the newest files are listed first
- tail: list oldest files
- lines: specify how many lines tail should show (number of backups - maximal number of backups many)
- xargs: do not run if there is nothing to do
- echo: print to be deleted files to the stdout
- cut: select only the second column (name of the files)
- rm: KKND
Note: Use find -type f --maxdepth 1 to ignore subfolders, as above.
Remove old Directories
As above, but with -type d and rm -rf:
find $backupRoot -mindepth 1 -maxdepth 1 -type d -printf '%T@\t%p\0' | sort --zero-terminated --numeric-sort --reverse | tail --zero-terminated --lines=$((nBackups-nBackupsToKeep>=0 ? nBackups-nBackupsToKeep : 0)) | xargs --null --no-run-if-empty --max-args=1 echo | cut --fields=2 | xargs --no-run-if-empty rm --verbose
Note:
- -mindepth: ignore the base directory
- -maxdepth: ignore sub-directories