#!/bin/bash if [[ $# -ge 1 && ( $# -gt 1 || ! "$1" =~ ^([0-9]|[1-9][0-9]*)(\.[0-9][0-9]*)?$ ) ]]; then printf 'Usage: uniqify-recent [N]\n' >&2 printf 'After a line is read from stdin, its duplicates are suppressed for N seconds (default: 60)\n' >&2 printf 'N may have a fractional part, e.g. 123456.789\n' >&2 exit 1 fi # EPOCHREALTIME was added in 4.4 if (( BASH_VERSINFO[0] < 4 || ( BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] < 4 ) )); then printf 'Error: this requires Bash 4.4 or higher\n' >&2 exit 1 fi limit=60000000 if [[ $# -eq 1 ]]; then if [[ "$1" == *.* ]]; then seconds="${1%.*}" fraction="${1#*.}" else seconds="$1" fraction= fi fraction="${fraction}000000" fraction="${fraction:0:6}" limit=$((seconds * 1000000 + fraction)) fi # Bash 5.2 added ridiculousness in arithmetic context expansion of associative arrays. Revert that nonsense. if (( BASH_VERSINFO[0] > 5 || ( BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 2 ) )); then BASH_COMPAT=51 fi declare -A lastseen lastclean=${EPOCHREALTIME/./} while IFS= read -r l; do now=${EPOCHREALTIME/./} if [[ ! -v 'lastseen[$l]' ]] || (( now - lastseen[\$l] > limit )); then printf '%s\n' "$l" lastseen["${l}"]="${now}" fi if (( now - lastclean > 10 * limit )); then # Purge old entries for k in "${!lastseen[@]}"; do if (( now - lastseen[\$k] > limit )); then unset -v 'lastseen[$k]' fi done lastclean="${now}" fi done