#!/bin/sh # xchg-rates # Written in 2023 by Lucas # CC0 1.0 Universal/Public domain - No rights reserved # # To the extent possible under law, the author(s) have dedicated all # copyright and related and neighboring rights to this software to the # public domain worldwide. This software is distributed without any # warranty. You should have received a copy of the CC0 Public Domain # Dedication along with this software. If not, see # . usage() { cat - <&2 Usage: ${0##*/} amount from to ${0##*/} -l Rates By Exchange Rate API - https://www.exchangerate-api.com EOF exit 1 } err() { printf "%s: %s\n" "${0##*/}" "$*" >&2 exit 1 } warn() { printf "%s: %s\n" "${0##*/}" "$*" >&2 } date_gt() { expr "X$1" ">" "X$2" >/dev/null } RATES_API=https://open.er-api.com/v6/latest/USD fetch_rates() { ftp -o "$RATES_JSON" "$RATES_API" } cachedir=${XDG_CACHE_HOME:-~/.cache}/xchg-rates mkdir -p "$cachedir" : ${RATES_JSON:=$cachedir/rates.json} do_list=false while getopts l flag; do case $flag in l) do_list=true ;; *) usage ;; esac done shift $(($OPTIND - 1)) if [ ! -f "$RATES_JSON" ]; then fetch_rates fi next_update_unix=$(jq -er .time_next_update_unix "$RATES_JSON") if [ $? -ne 0 ]; then fetch_rates else next_update=$(date -r "$next_update_unix" +%Y%m%dT%H%M%SZ) now=$(date +%Y%m%dT%H%M%SZ) if date_gt "$now" "$next_update"; then fetch_rates fi fi eol=$(jq -r '.time_eol_unix' "$RATES_JSON") if [ X"$eol" != X"0" ]; then warn "EOL set for $(date -j "$eol" +%Y%m%dT%H%M%SZ)" fi if $do_list; then jq -r '.rates | to_entries | .[].key' "$RATES_JSON" | sort exit $? fi if [ $# -ne 3 ]; then usage fi amount=$1 from=$(echo "$2" | tr a-z A-Z) to=$(echo "$3" | tr a-z A-Z) if ! jq --arg k "$from" -er '.rates | has($k)' "$RATES_JSON" >/dev/null; then err "no rate for $from" fi if ! jq --arg k "$to" -er '.rates | has($k)' "$RATES_JSON" >/dev/null; then err "no rate for $to" fi jq -r --arg from "$from" --arg to "$to" \ '.rates | [.[$from], .[$to]] | @tsv' "$RATES_JSON" | { read -r from to echo "$amount / $from * $to" | bc -l }