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.

Bash: The JMRemover

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.


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


  • -mindepth: ignore the base directory
  • -maxdepth: ignore sub-directories