awk is great for it because IRC (or at least the subset that the bot cares about) is relatively easy to parse, and shelling out the shell script that does the actual code evaluation and prints the result back is also fairly straightforward. Someone else used to have such a bot before but they had written it in Rust with a bajillion dependencies; if I had done that I would've had to update dependencies and redeploy it every other week. In contrast I deployed my awk version once and then basically haven't touched it in years.
The following caught my attention in the bash wrapper:
coproc GAWK {
gawk ...
}
<&"${GAWK[0]}" openssl s_client -connect "$IRC_SERVER" -quiet >&"${GAWK[1]}"
This is a cool way to make awk talk over a socket that isn't specific to Gawk. For sockets without TLS you can replace openssl(1) with nc(1). I'll keep it in mind.Edit: You can also use http://www.dest-unreach.org/socat/ and https://nmap.org/ncat/ with awk:
socat "OPENSSL:$host:$port" 'EXEC:awk ...'
socat "TCP:$host:$port" 'EXEC:awk ...'
ncat --exec '/usr/bin/awk ...' --ssl "$host:$port"
ncat -e '/usr/bin/awk ...' "$host:$port"The main difficulties were making the command-line interface and testing. You can't have flags that begin with a dash in portable AWK without a shell wrapper, and I didn't want one. I settled on manually parsing key=value options, which I don't think are bad, just nonstandard. They look like this:
humsize format=%6.1f%1s 'zero= empty'
There is no standard way to test AWK code. For testing I wrote a shell script that checks the program's outputs with grep: https://gitlab.com/dbohdan/humsize/-/blob/122aaed8d65dc8c285.... Don't do this; your tests should give the user (you) better feedback. You may think your program doesn't need anything but a couple of trivial tests that won't ever change; it is a pain when you inevitably are proven wrong. I should have instead had a directory with reference outputs and diffed against them to see what went wrong (my own example: https://github.com/dbohdan/initool/blob/72f65d3fde245ff8660c...).To ensure I didn't introduce portability issues, I set up testing against different awks in GitLab CI.
image: debian:bullseye-slim
before_script:
- apt update
- apt install -y busybox gawk mawk original-awk
- ln -s "$(which busybox)" awk
- busybox wget -O goawk.tar.gz https://github.com/benhoyt/goawk/releases/download/v1.21.0/goawk_v1.21.0_linux_amd64.tar.gz
- tar xzvf goawk.tar.gz
test:
script:
- AWK=false ./test || true
- AWK=./awk ./test
- AWK=gawk ./test
- AWK=./goawk ./test
- AWK=mawk ./test
- AWK=original-awk ./test
Edit: Rephrased and added a nicer shell test example.The problem was that the Garmin GPS data for a bike ride I had just completed had split into multiple rides. I used AWK to stitch together the data into one file. I also did some basic linear interpolation to fill in missing data points.
The GPS data is formatted as XML and I was able to parse it fairly robustly using AWK.
Depending on how the xml is structured, it can be possible to just pattern match on the tags if you have something simple to do.