#!/usr/bin/env bash # Remove all but the latest N versions of files matching given prefixes # Usage: prune-files -k 3 thisfileprefix [thatfileprefix] set -euo pipefail prune-files() { local -a PREFIXES local KEEP_INT=1 # default number of files to keep local DRY_RUN=false printHelpAndExit() { cat <<-'EOF' USAGE: prune-files -k 3 thisfileprefix [thatfileprefix] OPTIONS: -k, --keep NUMBER Keep NUMBER of the latest files that match each file prefix (Default: 1) -n, --dry-run Show what would be removed without actually deleting files -h, --help Print this help dialog and exit EOF [[ -z "$1" ]] && exit 0 || exit "$1" } parseInput() { local _input if _input=$(getopt -o hk:n -l help,keep:,dry-run -- "$@"); then eval set -- "$_input" while true; do case "$1" in -k|--keep) shift; KEEP_INT="$1" ;; -n|--dry-run) DRY_RUN=true ;; -h|--help) printHelpAndExit 0 ;; --) shift; break ;; esac shift done else echo "[ERROR] Incorrect option(s) provided" >&2 printHelpAndExit 1 fi if [[ $# -eq 0 ]]; then echo "[ERROR] At least one file prefix must be provided" >&2 printHelpAndExit 1 fi if ! [[ "$KEEP_INT" =~ ^[0-9]+$ ]] || [[ "$KEEP_INT" -lt 1 ]]; then echo "[ERROR] --keep must be a positive integer" >&2 exit 1 fi PREFIXES=("$@") } findAndRemove() { local prefix file count for prefix in "${PREFIXES[@]}"; do count=0 echo "[INFO] Processing files with prefix: $prefix" # List files matching the prefix sorted by modification time (latest first), # then remove all except the first KEEP_INT files. while IFS= read -r file; do if [[ "$DRY_RUN" == true ]]; then echo "[DRY-RUN] Would remove: $file" else echo "[INFO] Removing: $file" if ! rm -- "$file"; then echo "[ERROR] Failed to remove: $file" >&2 fi fi ((count++)) done < <( find . -maxdepth 1 -type f -name "${prefix}*" -printf '%T@ %p\n' 2>/dev/null | \ sort -rn | \ awk -v keep="$KEEP_INT" 'NR > keep {print $2}' ) if [[ $count -eq 0 ]]; then echo "[INFO] No files to remove for prefix: $prefix" else echo "[INFO] Processed $count file(s) for prefix: $prefix" fi done } main() { parseInput "$@" findAndRemove } main "$@" } # Allow script to be safely sourced if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then prune-files "$@" exit $? fi