|
|
@@ -0,0 +1,52 @@ |
|
|
|
#!/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 |