#!/bin/bash # inflate - adjust a historical USD amount for inflation using BLS CPI data # # Finds the equivalent buying power today* of a historical amount of USD # e.g. "$1234.56 in Feb 1980 is equivalent to $4915.94 in Jun 2024" # Data source: https://data.bls.gov/cgi-bin/cpicalc.pl # * Most recent month available is used, typically a 1-month delay # # Usage: # inflate [month] # (where month is an integer in [1,12], default 1) # # Sample output with stderr: # $ inflate 150 1970 9 # $150.00: Sep 1970 -> Jun 2024 # 1202.20 # Sample output without stderr: # $ inflate 150 1970 9 2>/dev/null # 1202.20 _inflate() ( local SCRIPT_NAME; SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")" case "${BASH_SOURCE[0]}" in /dev/*|/proc/*) SCRIPT_NAME="" ;; esac case "$SCRIPT_NAME" in ""|bash|sh|zsh|dash) SCRIPT_NAME="inflate" ;; esac _error() { echo "[ERR][$SCRIPT_NAME] $*" >&2; } _show_help() { local s; [ -t 1 ] && s=$'\033[4m' local r; [ -t 1 ] && r=$'\033[24m' echo "NAME" echo " $SCRIPT_NAME - adjust a historical USD amount for inflation" echo "SYNOPSIS" echo " $SCRIPT_NAME ${s}amount${r} ${s}year${r} [${s}month${r}]" echo " $SCRIPT_NAME -h" echo "DESCRIPTION" echo " Fetches CPI data from the US Bureau of Labor Statistics and prints" echo " the equivalent buying power in the most recent month available." echo " The adjusted amount is printed to stdout; a summary line (e.g." echo " \"\$150.00: Sep 1970 -> Jun 2024\") is printed to stderr." echo " BLS CPI data is available for years 1913 through the most recent" echo " month (typically a 1-2 month delay)." echo "OPTIONS" echo " ${s}amount${r} Dollar amount to adjust (e.g. 150, 1234.56)" echo " ${s}year${r} Historical year (1913 or later)" echo " ${s}month${r} Month as integer 1-12 (default: 1 / January)" echo " -h, --help Show this help message" echo "EXIT STATUS" echo " 0 Success" echo " 1 Runtime failure (BLS calculator response didn't yield a number)" echo " 2 Usage error (missing amount, missing year, month out of range)" echo " 3 Dependency error (curl missing)" echo "DEPENDENCIES" echo " curl" echo "CAVEATS" echo " Requires network connectivity; the BLS inflation calculator at" echo " https://data.bls.gov/cgi-bin/cpicalc.pl must be reachable. Data is" echo " fetched on every invocation (no local cache)." } case "$1" in -h|--help) _show_help; return 0 ;; esac if ! command -v curl >/dev/null 2>&1; then _error "curl is required" return 3 fi [ "$1" ] || { _error "amount is required. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } [ "$2" ] || { _error "year is required. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } local amount; amount="$(printf '%.2f' "$1")" local input_year="$2" local input_month="${3:-1}" # default to January # Validate month range before network request - an invalid month produces a # confusing downstream error (blank month name in the failure message) if [ "$input_month" -lt 1 ] || [ "$input_month" -gt 12 ]; then _error "month must be in range [1, 12] (got: $input_month). Run \`$SCRIPT_NAME -h\` for usage" return 2 fi # Zero-pad month if necessary - printf is not good here because numbers with leading zeroes can be interpreted as octal [ "$input_month" -lt 10 ] && input_month="0${input_month#0}" # US Bureau of Labor Statistics inflation calculator local CALCULATOR_URL="https://data.bls.gov/cgi-bin/cpicalc.pl" # Month names array with a placeholder at index 0, so that 1 is January and 12 is December local MONTHS=(ERR Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) # Get the most recent month of data available (e.g. 202406), from the second dropdown local recent_year_month; recent_year_month="$(curl -fsS "$CALCULATOR_URL" \ | grep 'selected="selected"' \ | tail -n 1 \ | sed -n 's/.*value="\([^"]*\)".*/\1/p')" local recent_year="${recent_year_month:0:4}" local recent_month="${recent_year_month:4:2}" # Format the input and recent year-month dates into a more readable format, e.g. "Jan 2024" rather than "202401" # "10#" is necessary to avoid numbers with a leading 0 from being interpreted as octal - alternatively ${MONTHS[${input_month#0}]} local input_date_formatted="${MONTHS[10#$input_month]} $input_year" local recent_date_formatted="${MONTHS[10#$recent_month]} $recent_year" # Fetch the data and extract the adjusted amount local result; result="$(curl -fsS "$CALCULATOR_URL?cost1=$amount&year1=$input_year$input_month&year2=$recent_year$recent_month" \ | sed -n '/id="answer"/{s/^.*\$//;s/<.*$//;s/,//g;p;}')" if [ -z "$result" ]; then _error "Failed to convert \$$amount from $input_date_formatted to $recent_date_formatted" _error "BLS CPI data is available for years 1913 through the most recent month (got: $input_year)" return 1 fi # Print the result, with details to stderr only in case just the number is needed (i.e. if it's called from another script) echo "\$$amount: $input_date_formatted -> $recent_date_formatted" >&2 echo "$result" ) _inflate "$@" __inflate_rc=$? unset -f _inflate if [ -n "${BASH_SOURCE[0]}" ] && [ "${BASH_SOURCE[0]}" != "$0" ]; then eval "unset __inflate_rc; return $__inflate_rc" fi eval "unset __inflate_rc; exit $__inflate_rc"