Rotate a log file when it grows too large

Bash
#!/usr/bin/env bash
# Rotate a log file once it exceeds a size, keeping gzipped backups.
set -euo pipefail

log_file="${1:?usage: $0 LOG_FILE [MAX_BYTES] [KEEP]}"
max_bytes="${2:-10485760}" # rotate at 10 MiB by default
keep="${3:-5}"
((keep >= 1)) || { printf 'keep must be >= 1\n' >&2; exit 64; }

if [[ ! -f $log_file ]]; then
  printf 'not a regular file: %s\n' "$log_file" >&2
  exit 1
fi
size=$(wc -c < "$log_file")
if ((size < max_bytes)); then
  exit 0
fi

# Drop the oldest backup, then shift the rest up by one.
rm -f -- "$log_file.$keep.gz"
for ((i = keep - 1; i >= 1; i--)); do
  if [[ -f "$log_file.$i.gz" ]]; then
    mv -- "$log_file.$i.gz" "$log_file.$((i + 1)).gz"
  fi
done

# copytruncate: keep writers that still hold the file descriptor working.
cp -- "$log_file" "$log_file.1"
: > "$log_file"
gzip -f -- "$log_file.1"
printf 'rotated %s at %s bytes\n' "$log_file" "$size"