6 expire-iso8601 [<options>] <unit-in-seconds> <slop-in-seconds>
7 <min-interval-in-units> <number-to-keep>
8 [<min-interval-in-units> <number-to-keep> ...]
10 -n do not really delete
11 -r recursive removal (rm -r)
13 /home/ian/junk/expire-iso8601 86400 10000 1 14 7 4
14 uses units of 86400s (1 day) with a slop of 10ks;
15 it keeps 14 daily items
16 (that is 14 items, dated no less than 86400-10000s apart)
18 (that is 7 items, dated no less than 7*86400-10000s apart)
19 the 14 daily and 7 weekly items may be the same, or not
20 There is no need to sort the list of interval/number pairs.
25 16 catastrophic failure
30 badusage () { echo >&2 "bad usage: $*"; usage >&2; trap '' 0; exit 8; }
32 #-------------------- argument parsing --------------------
35 while [ $# -ge 1 ]; do
39 --help) usage; exit 0 ;;
40 --*) badusage "unknown option $arg" ;;
45 *) badusage "unknown option ${1:0:2}" ;;
48 if test "x$arg" != x-; then set -- "$arg" "$@"; fi
50 *) set "$arg" "$@"; break ;;
54 [ $# -ge 4 ] || badusage 'too few arguments'
60 [ $(($# % 2)) = 0 ] || badusage 'odd keep arguments (need min/extent pairs)'
64 [ "x${1##*[^0-9]}" = "x$1" ] || badusage "$2 must be all digits"
65 [ x$1 ] || badusage "$2 must be nonempty"
68 while [ $# -gt 0 ]; do
69 min=$1; shift; extent=$1; shift
71 alldigits $extent extent
74 #-------------------- scanning the directory ----------
76 # We build in $l a list of the relevant filenames and the time_t's
79 # Each entry in $l is $time_t/$filename, and the list is
80 # newline-separated for the benefit of sort(1).
87 ????-??-??T[0-2][0-9]+[0-9][0-9][0-9][0-9]|\
88 ????-??-??T[0-2][0-9]:[0-6][0-9]+[0-9][0-9][0-9][0-9]|\
89 ????-??-??T[0-2][0-9]:[0-6][0-9]:[0-6][0-9]+[0-9][0-9][0-9][0-9])
90 conv="${cn%T*} ${cn#*T}";;
92 echo >&2 "ignoring $cn"
95 cs=$(date -d "$conv" +%s)
100 #-------------------- main computation --------------------
102 # We process each minimum/extent pair, to have it select a bunch of
103 # versions to keep. We annotate entries in $l: if we are keeping
104 # an entry we prepend a colon.
106 # For each minimum/extent pair we look at the list from most recent
108 # ie in order of increasing age
109 # ie in order of decreasing time_t
110 # and each time we're more than min older than the last item we kept,
111 # we mark the item to keep, until we have as many as we want.
113 # We build the new list (space-separated) in lnew.
121 while [ $# != 0 ]; do
122 min=$(( $1 * $unit - $slop ))
128 cn=${ce#*/}; cl=${ce%%/*}; cs=${cl#:}
129 if [ $wantcount != 0 ]; then
131 [ $(( $ls - $cs )) -ge $min ]; then
132 echo "keep (for $1 $2) $cn"
135 wantcount=$(( $wantcount - 1 ))
140 if [ $wantcount != 0 ];then
141 echo "insufficient (for $1 $2) by $wantcount"
147 #-------------------- execution --------------------
152 nonbroken_echo () { (echo "$@"); }
153 # While we have subprocesses, we have to avoid bash calling write(1,...)
154 # because of a bug in bash (Debian #382798), so we arrange for a subshell
163 nonbroken_echo "expire $cn"
164 echo $rm $recurse -- $cn &
171 nonbroken_echo "all running"
175 wait $job || exitstatus=4
178 if [ $exitstatus = 0 ]; then
181 echo "complete, but problems deleting"