Skip to content

Instantly share code, notes, and snippets.

@ethaniel
Created December 31, 2024 04:00
Show Gist options
  • Save ethaniel/6e12d60fd02a8274b09c6d74260abf15 to your computer and use it in GitHub Desktop.
Save ethaniel/6e12d60fd02a8274b09c6d74260abf15 to your computer and use it in GitHub Desktop.
Delete oldest files in a folder until total used disk space is below a threshold
#!/usr/bin/env bash
#
# delete_oldest_until_threshold.sh
#
# Repeatedly deletes the oldest file in a folder until
# disk usage is below a specified threshold.
#
# Usage:
# ./delete_oldest_until_threshold.sh -p /path/to/folder [-t threshold_in_percentage]
#
# Example:
# ./delete_oldest_until_threshold.sh -p /var/log -t 85
# ./delete_oldest_until_threshold.sh -p /mnt/data # uses default threshold=80
######################################
# DEFAULTS
######################################
THRESHOLD=80
######################################
# PARSE ARGUMENTS
######################################
usage() {
echo "Usage: $0 -p <path> [-t <threshold>]"
echo " -p PATH : Path to the target directory (mandatory)."
echo " -t THRESHOLD : Disk usage threshold (optional, default=$THRESHOLD)."
exit 1
}
# Use getopts to handle -p and -t
while getopts ":p:t:" opt; do
case $opt in
p)
TARGET_DIR="$OPTARG"
;;
t)
THRESHOLD="$OPTARG"
;;
\?)
echo "Invalid option: -$OPTARG" >&2
usage
;;
:)
echo "Option -$OPTARG requires an argument." >&2
usage
;;
esac
done
# Ensure path is provided
if [ -z "$TARGET_DIR" ]; then
echo "Error: Path (-p) is mandatory."
usage
fi
######################################
# FUNCTIONS
######################################
get_usage() {
# Return the usage of the partition containing $TARGET_DIR
df --output=pcent "$TARGET_DIR" 2>/dev/null \
| tail -n 1 \
| tr -dc '0-9'
}
######################################
# MAIN SCRIPT
######################################
# 1) Get current disk usage
CURRENT_USAGE=$(get_usage)
if [ -z "$CURRENT_USAGE" ]; then
echo "Error: Could not determine disk usage for '$TARGET_DIR'. Check that it exists."
exit 1
fi
echo "Current usage: $CURRENT_USAGE%. Threshold: $THRESHOLD%."
# If we are already below threshold, no action needed
if [ "$CURRENT_USAGE" -lt "$THRESHOLD" ]; then
echo "Disk usage is already below threshold. No action taken."
exit 0
fi
# 2) Collect files in ascending order of modification time (oldest first)
# -printf '%T@\t%p\n': prints epoch modification time + path
# sort -k1,1n: sorts by numeric timestamp ascending
# cut -f2-: removes the first column (timestamps), leaving just file paths
FILES=$(find "$TARGET_DIR" -type f -printf "%T@\t%p\n" 2>/dev/null \
| sort -k1,1n \
| cut -f2-)
# Convert the list of files into an array
IFS=$'\n' read -r -d '' -a FILE_ARRAY <<< "$(printf '%s\n' "$FILES")"
# 3) If no files found, exit
if [ "${#FILE_ARRAY[@]}" -eq 0 ]; then
echo "No files found in '$TARGET_DIR' to delete."
exit 0
fi
# 4) Delete files (oldest first) until usage is below threshold
for FILE in "${FILE_ARRAY[@]}"; do
if [ -f "$FILE" ]; then
echo "Deleting oldest file: $FILE"
rm -f "$FILE"
# Re-check usage after each deletion
CURRENT_USAGE=$(get_usage)
echo "Disk usage is now: $CURRENT_USAGE%."
if [ "$CURRENT_USAGE" -lt "$THRESHOLD" ]; then
echo "Disk usage is now below threshold ($THRESHOLD%). Done."
exit 0
fi
fi
done
# 5) If we made it here, we removed all files in the target directory
# but are still above threshold
echo "All files in '$TARGET_DIR' have been removed, yet usage is still $CURRENT_USAGE%."
echo "Further action might be necessary."
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment