#!/bin/sh # The MIT License (MIT) # # Copyright © 2024 pacman64 # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # bu [time] # bu [quantity] [unit] # bu [quantity] ft [quantity] in # bu [quantity] lb [quantity] oz # # Better Units # # # Turn common measurement units used in the US into their international # counterparts. Even the mixed-unit cases ft-in and lb-oz are accepted, # when given 2 number-unit pairs. # # Besides those, time units in common use, such as minutes, hours, days, # and weeks have been added for convenience: these are all turned into # seconds. # # Even time-formats HH:MM:SS and MM:SS are supported: the seconds part # can optionally have decimal digits, and no unit is needed, as those # formats clearly identify their time-related units by themselves. # # # You may also want to use the shortcut below, instead of using this # script directly. # # # Change Units converts common units into more convenient equivalents # cu() { # ( set -o pipefail && bu "$@" | awk '{ print $(NF-1), $NF }' ) # } # handle help options case "$1" in -h|--h|-help|--help) awk '/^# +bu/, /^$/ { gsub(/^# ?/, ""); print }' "$0" exit 0 ;; esac # normalize the unit name right away, to avoid re-running the same apps unitname="$(echo ${2} | tr [:upper:] [:lower:] | tr -d - | tr -d _)" case "${unitname}" in # handle that mixed-unit abomination using feet and inches ft|feet|foot) case "$(echo ${4} | tr [:upper:] [:lower:])" in in|inch|inches) y=$(echo "scale=4; 0.3048*${1} + 0.0254*${3}" | bc) printf "%12.4f ft %12.4f in = %12.4f m\n" \ "${1}" "${3}" "${y}" exit $? ;; esac ;; # handle hertz, megahertz, and gigahertz: even some old-fashioned names # are supported; the name `cycle` is handled as an angular unit instead hz|hertz) y=$(echo "scale=4; 1/${1}" | bc) printf "%12.4f hz = %12.4f s\n" "${1}" "${y}" exit $? ;; mhz|megahertz|megacycle|megacycles) y=$(echo "scale=12; 1/(1000000*${1})" | bc) printf "%12.4f hz = %12.12f s\n" "${1}" "${y}" exit $? ;; ghz|gigahertz|gigacycle|gigacycles) y=$(echo "scale=12; 1/(1000000000*${1})" | bc) printf "%12.4f hz = %12.12f s\n" "${1}" "${y}" exit $? ;; # handle that mixed-unit abomination using pounds and weight-ounces lb|lbs|pound|pounds) case "$(echo ${4} | tr [:upper:] [:lower:])" in oz|ozs|ounce|ounces) y=$(echo "scale=4; 0.45359237*${1} + 0.028349523*${3}" | bc) printf "%12.4f lb %12.4f oz = %12.4f kg\n" \ "${1}" "${3}" "${y}" exit $? ;; esac ;; # handle converting numbers from base 2 into base-10 ones bin|binary|base2|b2|0b|bit|bits|2) # check for valid binary values, quitting whole script on failure if echo "$1" | grep -E -q '.*[^01].*'; then printf "\x1b[31minvalid binary number %s\x1b[0m\n" "$1" \ > "/dev/stderr" exit 1 fi decval=$(echo "ibase=2; ${1}" | bc) printf "%s bin = %s dec\n" "${1}" "${decval}" exit $? ;; # handle converting numbers from base 8 into base-10 ones oct|octal|base8|b8|0o|o|8) # check for valid binary values, quitting whole script on failure if echo "$1" | grep -E -q '.*[^0-7].*'; then printf "\x1b[31minvalid octal number %s\x1b[0m\n" "$1" \ > "/dev/stderr" exit 1 fi decval=$(echo "ibase=8; ${1}" | bc) printf "%s oct = %s dec\n" "${1}" "${decval}" exit $? ;; # handle converting numbers from base 16 into base-10 ones hex|hexa|hexadec|hexadecimal|base16|b16|0x|x|16) hexval=$(echo "${1}" | sed 's-^0x--' | tr '[:lower:]' '[:upper:]') if echo "${hexval}" | grep -E -q '.*[^0-9a-fA-F].*'; then printf "\x1b[31minvalid octal number %s\x1b[0m\n" "$1" \ > "/dev/stderr" exit 1 fi decval=$(echo "ibase=16; ${hexval}" | bc) printf "%s hex = %s dec\n" "${hexval}" "${decval}" exit $? ;; esac # warn users who might wrongly think multiple pairs of args are allowed # in general: only ft/in and lb/oz are allowed if [ $# -gt 2 ]; then printf "\x1b[31m" >&2 printf "only 1 or 2 args allowed, unless using ft/in or " >&2 printf "lb/oz mixed-units value-pairs" >&2 printf "\x1b[0m\n" >&2 exit 1 fi # handle all other unit-conversions awk -v x="${1}" -v unit="${unitname}" ' # normalize both quantities and units, and handle special cases for units BEGIN { # ignore underscores in numbers, thus `allowing` them for convenience gsub(/[_]/, "", x) # normalize unit names for later lookup unit = tolower(unit) gsub(/[ _.-]/, "", unit) # handle fahrenheit temperatures if (unit == "f" || unit == "fahrenheit") { printf "%12.4f °F = %12.4f °C\n", x, (x - 32) / (5.0/9.0) ok = 1 exit 0 } # handle kelvin temperatures if (unit == "k" || unit == "kelvin") { printf "%12.4f °K = %12.4f °C\n", x, x - 273.15 ok = 1 exit 0 } # handle the mm:ss time format if (match(x, /^[0-9]+:[0-9]{1,2}(\.[0-9]*)?$/)) { split(x, hms, ":") printf "%s = %12.4f s\n", x, 60*hms[1] + hms[2] ok = 1 exit 0 } # handle the hh:mm:ss time format if (match(x, /^[0-9]+:[0-9]{1,2}:[0-9]{1,2}(\.[0-9]*)?$/)) { split(x, hms, ":") printf "%s = %12.4f s\n", x, 3600*hms[1] + 60*hms[2] + hms[3] ok = 1 exit 0 } # handle seconds, turning the number into the hh:mm:ss time format if (unit == "s") { h = (x - x % 3600) / 3600 m = (x % 3600) / 60 s = x % 60 printf "%s s = %02d:%02d:%05.2f\n", x, h, m, s ok = 1 exit 0 } } # match the unit given to its built-in entry, if present $1 == unit { printf "%12.4f %s = %12.4f %s\n", x, $2, $3*x, $4 ok = 1 exit 0 } # tell user when no match was found, and fail the whole surrounding tool if so END { if (!ok) { fs = "\x1b[31munit name/alias `%s` not supported\n\x1b[0m" printf fs, unit > "/dev/stderr" exit 1 } } ' << 'EOF' ac ac 4046.8564224 m² acre ac 4046.8564224 m² acres ac 4046.8564224 m² angle deg 0.0174532925199 rad andeg deg 0.0174532925199 rad angdeg deg 0.0174532925199 rad angular deg 0.0174532925199 rad angulardeg deg 0.0174532925199 rad angulardegree deg 0.0174532925199 rad angulardegrees deg 0.0174532925199 rad angledeg deg 0.0174532925199 rad angledegree deg 0.0174532925199 rad angledegrees deg 0.0174532925199 rad barrel bbl 158.9873 L barrels bbl 158.9873 L bbl bbl 158.9873 L cfeet ft³ 0.028316846592 m³ cfoot ft³ 0.028316846592 m³ cft ft³ 0.028316846592 m³ cufeet ft³ 0.028316846592 m³ cufoot ft³ 0.028316846592 m³ cuft ft³ 0.028316846592 m³ cup cup 0.23658824 L cups cup 0.23658824 L cyc tr 6.2831853071796 rad cycle tr 6.2831853071796 rad cycles tr 6.2831853071796 rad d day 86400 s day day 86400 s days day 86400 s deg deg 0.0174532925199 rad degree deg 0.0174532925199 rad degrees deg 0.0174532925199 rad in in 2.54 cm inch in 2.54 cm inches in 2.54 cm ft ft 0.3048 m ft2 ft² 0.09290304 m² ft3 ft³ 0.028316846592 m³ ft² ft² 0.09290304 m² ft³ ft³ 0.028316846592 m³ feet ft 0.3048 m feet2 ft² 0.09290304 m² feet3 ft³ 0.028316846592 m³ feet² ft² 0.09290304 m² feet³ ft³ 0.028316846592 m³ floz floz 29.5735295625 mL foot ft 0.3048 m foot2 ft² 0.09290304 m² foot3 ft³ 0.028316846592 m³ foot² ft² 0.09290304 m² foot³ ft³ 0.028316846592 m³ ga gal 3.785411784 L gal gal 3.785411784 L gallon gal 3.785411784 L gallons gal 3.785411784 L gb gb 1073741824 bytes gib gb 1073741824 bytes gon grad 0.0157079632679 rad gons grad 0.0157079632679 rad grad grad 0.0157079632679 rad gradian grad 0.0157079632679 rad gradians grad 0.0157079632679 rad h hr 3600 s hour hr 3600 s hours hr 3600 s hr hr 3600 s hrs hr 3600 s kb kb 1024 bytes kib kb 1024 bytes lb lb 0.45359237 kg lbs lb 0.45359237 kg mb mb 1048576 bytes mi mi 1.609344 km mib mb 1048576 bytes mih mph 1.609344 kph mi2 mi² 2.5899881103360 km² mi² mi² 2.5899881103360 km² mil mrad 0.001 rad millirad mrad 0.001 rad milliradian mrad 0.001 rad milliradians mrad 0.001 rad mile mi 1.609344 km mile² mi² 2.5899881103360 km² miles mi 1.609344 km miles² mi² 2.5899881103360 km² min min 60 s minute min 60 s minutes min 60 s mpg mpg 0.425143707 kpl mph mph 1.609344 kph mrad mrad 0.001 rad nmi nmi 1.852 km nmile nmi 1.852 km nmiles nmi 1.852 km oilbarrel bbl 158.9873 L oilbarrels bbl 158.9873 L oz oz 28.349523125 g ounce oz 28.349523125 g ounces oz 28.349523125 g pint pt 473.176473 mL pla tr 6.2831853071796 rad pound lb 0.45359237 kg pounds lb 0.45359237 kg psi psi 6894.757293168 Pa pt pt 473.176473 mL rad rad 57.295779513082 deg radian rad 57.295779513082 deg radians rad 57.295779513082 deg rev tr 6.2831853071796 rad revolution tr 6.2831853071796 rad revolutions tr 6.2831853071796 rad sfeet ft² 0.09290304 m² sfoot ft² 0.09290304 m² sft ft² 0.09290304 m² smi mi² 2.5899881103360 km² smile mi² 2.5899881103360 km² smiles mi² 2.5899881103360 km² syard yd² 0.83612736 m² syards yd² 0.83612736 m² syd yd² 0.83612736 m² syds yd² 0.83612736 m² sqfeet ft² 0.09290304 m² sqfoot ft² 0.09290304 m² sqft ft² 0.09290304 m² sqmi mi² 2.5899881103360 km² sqmile mi² 2.5899881103360 km² sqmiles mi² 2.5899881103360 km² sqyard yd² 0.83612736 m² sqyards yd² 0.83612736 m² sqyd yd² 0.83612736 m² sqyds yd² 0.83612736 m² tb tb 1099511627776 bytes tib tb 1099511627776 bytes ton ton 907.18474 kg tr tr 6.2831853071796 rad turn tr 6.2831853071796 rad turns tr 6.2831853071796 rad ukpint ukpt 568.26125 mL ukpt ukpt 568.26125 mL uspint pt 473.176473 mL uspt pt 473.176473 mL w wk 604800 s week wk 604800 s weeks wk 604800 s wk wk 604800 s wks wk 604800 s yard yd 0.9144 m yard2 yd² 0.83612736 m² yards yd 0.9144 m yards2 yd² 0.83612736 m² yd yd 0.9144 m yds yd 0.9144 m yd² yd² 0.83612736 m² yds² yd² 0.83612736 m² EOF