!/bin/sh
anniv - generate anniversary reminders for agenda.txt
SPDX-FileCopyrightText: 2023 Daniel Kalak
SPDX-License-Identifier: GPL-3.0-or-later
This program reads lines from stdin and prints lines to stdout,
sorted. It expects the input lines to be of a format like this:
John Doe (my best friend) (* 1983-06-21)
These could be the first lines of a group of text files (e.g. with
contact information) that you could assemble with "head -qn1 *.txt".
Then, if the current year is 2023, the output would look like this:
2023-06-21 * John Doe (my best friend) (1983, 40)
If the year specified in the input is 0000 (i.e. if you had
"0000-06-21" in the example), the last parenthesis in the output (i.e.
" (1983, 40)" in the example) is omitted. (This is for cases where the
year is unknown.)
You can specify an arbitrary "current year" and an arbitrary symbol on
the command line. The symbol needs to be a Basic Regular Expression as
used by GNU sed. (For example, you could use "+" for deaths or "oo"
for marriages, etc.) By default, the current year at invocation and
the symbol "*" (to symbolize a birthday) are used.
The program only checks if there is a space followed by an opening
parenthesis (i.e. " (") at some point in an input line, and if that is
the case, it checks if there is the symbol followed by a space
followed by an ISO date (e.g. "* 1983-06-21") at some point after that
parenthesis (but before it is closed, if it ever is). Everything
before the " (" is treated as the "name", and everything else (other
than the date) is discarded. This lets you put arbitrary stuff into
the parenthesis (e.g. multiple dates with different symbols) or after
it.
This program depends on GNU awk, the GNU coreutils, and GNU sed. It
exits 0 on success and 1 on bad usage. If it encounters an input line
that is not in the format specified above, it redirects it to stderr,
along with a warning; this does not affect the other output lines (on
stdout) and the program still exits 0.
usage_quit() {
cat <<- EOF >&2
Usage: $0 [YEAR [SYMBOL]]
EOF
exit 1
}
year="${1:-$(date +%Y)}"
symbol="${2:-*}"
isodate='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
case "$year" in
[0-9][0-9][0-9][0-9]) ;;
esac
sed '
s/\(.*\) ([^)]*\('"$symbol"'\) \('"$isodate"'\).*/\3 \2 \1/
t
s/^/ERROR/' |
At this stage in the pipeline, the example input line given above
would look like "1983-06-21 * John Doe (my best friend)". Faulty input
lines have a prepended "ERROR" tag (without separators) and are left
unchanged otherwise.
while read -r line
do
case "$line" in
ERROR*) printf 'Wrong input format: %s\n' "${line#ERROR}" >&2 ;;
*) printf '%s\n' "$line"
esac
done |
At this stage in the pipeline, the faulty lines prepended with "ERROR"
have been redirected to stderr.
awk -v "year=$year" '
{
birthyear = substr($0, 1, 4)
sub(birthyear, year)
if (birthyear != "0000")
$0 = $0 " (" birthyear ", " year-birthyear ")"
print
}' |
At this stage in the pipeline, the "birth" year at the beginning of a
line has been replaced with the current year, and the " (1983, 40)"
parenthesis in the example has been appended for all years that are
not "0000". All that is left to do is to sort.
LC_ALL=C sort
Proxy Information
- Original URL
- gemini://dkalak.de/software/anniv.sh
- Status Code
- Success (20)
- Meta
text/plain
- Capsule Response Time
- 108.828758 milliseconds
- Gemini-to-HTML Time
- 1.775541 milliseconds
This content has been proxied by September (3851b).