File: bu.sh 1 #!/bin/sh 2 3 # The MIT License (MIT) 4 # 5 # Copyright © 2024 pacman64 6 # 7 # Permission is hereby granted, free of charge, to any person obtaining a copy 8 # of this software and associated documentation files (the “Software”), to deal 9 # in the Software without restriction, including without limitation the rights 10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 # copies of the Software, and to permit persons to whom the Software is 12 # furnished to do so, subject to the following conditions: 13 # 14 # The above copyright notice and this permission notice shall be included in 15 # all copies or substantial portions of the Software. 16 # 17 # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 # SOFTWARE. 24 25 26 # bu [time] 27 # bu [quantity] [unit] 28 # bu [quantity] ft [quantity] in 29 # bu [quantity] lb [quantity] oz 30 # 31 # Better Units 32 # 33 # 34 # Turn common measurement units used in the US into their international 35 # counterparts. Even the mixed-unit cases ft-in and lb-oz are accepted, 36 # when given 2 number-unit pairs. 37 # 38 # Besides those, time units in common use, such as minutes, hours, days, 39 # and weeks have been added for convenience: these are all turned into 40 # seconds. 41 # 42 # Even time-formats HH:MM:SS and MM:SS are supported: the seconds part 43 # can optionally have decimal digits, and no unit is needed, as those 44 # formats clearly identify their time-related units by themselves. 45 # 46 # 47 # You may also want to use the shortcut below, instead of using this 48 # script directly. 49 # 50 # # Change Units converts common units into more convenient equivalents 51 # cu() { 52 # ( set -o pipefail && bu "$@" | awk '{ print $(NF-1), $NF }' ) 53 # } 54 55 56 # handle help options 57 case "$1" in 58 -h|--h|-help|--help) 59 # show help message, extracting the info-comment at the start 60 # of this file, and quit 61 awk '/^# +bu/, /^$/ { gsub(/^# ?/, ""); print }' "$0" 62 exit 0 63 ;; 64 esac 65 66 # normalize the unit name right away, to avoid re-running the same apps 67 unitname="$(echo ${2} | tr [:upper:] [:lower:] | tr -d - | tr -d _)" 68 69 case "${unitname}" in 70 # handle that mixed-unit abomination using feet and inches 71 ft|feet|foot) 72 case "$(echo ${4} | tr [:upper:] [:lower:])" in 73 in|inch|inches) 74 y=$(echo "scale=4; 0.3048*${1} + 0.0254*${3}" | bc) 75 printf "%12.4f ft %12.4f in = %12.4f m\n" \ 76 "${1}" "${3}" "${y}" 77 exit $? 78 ;; 79 esac 80 ;; 81 82 # handle hertz, megahertz, and gigahertz: even some old-fashioned names 83 # are supported; the name `cycle` is handled as an angular unit instead 84 hz|hertz) 85 y=$(echo "scale=4; 1/${1}" | bc) 86 printf "%12.4f hz = %12.4f s\n" "${1}" "${y}" 87 exit $? 88 ;; 89 mhz|megahertz|megacycle|megacycles) 90 y=$(echo "scale=12; 1/(1000000*${1})" | bc) 91 printf "%12.4f hz = %12.12f s\n" "${1}" "${y}" 92 exit $? 93 ;; 94 ghz|gigahertz|gigacycle|gigacycles) 95 y=$(echo "scale=12; 1/(1000000000*${1})" | bc) 96 printf "%12.4f hz = %12.12f s\n" "${1}" "${y}" 97 exit $? 98 ;; 99 100 # handle that mixed-unit abomination using pounds and weight-ounces 101 lb|lbs|pound|pounds) 102 case "$(echo ${4} | tr [:upper:] [:lower:])" in 103 oz|ozs|ounce|ounces) 104 y=$(echo "scale=4; 0.45359237*${1} + 0.028349523*${3}" | bc) 105 printf "%12.4f lb %12.4f oz = %12.4f kg\n" \ 106 "${1}" "${3}" "${y}" 107 exit $? 108 ;; 109 esac 110 ;; 111 112 # handle converting numbers from base 2 into base-10 ones 113 bin|binary|base2|b2|0b|bit|bits|2) 114 # check for valid binary values, quitting whole script on failure 115 if echo "$1" | grep -E -q '.*[^01].*'; then 116 printf "\x1b[31minvalid binary number %s\x1b[0m\n" "$1" \ 117 > "/dev/stderr" 118 exit 1 119 fi 120 121 decval=$(echo "ibase=2; ${1}" | bc) 122 printf "%s bin = %s dec\n" "${1}" "${decval}" 123 exit $? 124 ;; 125 126 # handle converting numbers from base 8 into base-10 ones 127 oct|octal|base8|b8|0o|o|8) 128 # check for valid binary values, quitting whole script on failure 129 if echo "$1" | grep -E -q '.*[^0-7].*'; then 130 printf "\x1b[31minvalid octal number %s\x1b[0m\n" "$1" \ 131 > "/dev/stderr" 132 exit 1 133 fi 134 135 decval=$(echo "ibase=8; ${1}" | bc) 136 printf "%s oct = %s dec\n" "${1}" "${decval}" 137 exit $? 138 ;; 139 140 # handle converting numbers from base 16 into base-10 ones 141 hex|hexa|hexadec|hexadecimal|base16|b16|0x|x|16) 142 hexval=$(echo "${1}" | sed 's-^0x--' | tr '[:lower:]' '[:upper:]') 143 if echo "${hexval}" | grep -E -q '.*[^0-9a-fA-F].*'; then 144 printf "\x1b[31minvalid octal number %s\x1b[0m\n" "$1" \ 145 > "/dev/stderr" 146 exit 1 147 fi 148 149 decval=$(echo "ibase=16; ${hexval}" | bc) 150 printf "%s hex = %s dec\n" "${hexval}" "${decval}" 151 exit $? 152 ;; 153 esac 154 155 # warn users who might wrongly think multiple pairs of args are allowed 156 # in general: only ft/in and lb/oz are allowed 157 if [ $# -gt 2 ]; then 158 printf "\x1b[31m" >&2 159 printf "only 1 or 2 args allowed, unless using ft/in or " >&2 160 printf "lb/oz mixed-units value-pairs" >&2 161 printf "\x1b[0m\n" >&2 162 exit 1 163 fi 164 165 # handle all other unit-conversions 166 awk -v x="${1}" -v unit="${unitname}" ' 167 # normalize both quantities and units, and handle special cases for units 168 BEGIN { 169 # ignore underscores in numbers, thus `allowing` them for convenience 170 gsub(/[_]/, "", x) 171 172 # normalize unit names for later lookup 173 unit = tolower(unit) 174 gsub(/[ _.-]/, "", unit) 175 176 # handle fahrenheit temperatures 177 if (unit == "f" || unit == "fahrenheit") { 178 printf "%12.4f °F = %12.4f °C\n", x, (x - 32) / (5.0/9.0) 179 ok = 1 180 exit 0 181 } 182 183 # handle kelvin temperatures 184 if (unit == "k" || unit == "kelvin") { 185 printf "%12.4f °K = %12.4f °C\n", x, x - 273.15 186 ok = 1 187 exit 0 188 } 189 190 # handle the mm:ss time format 191 if (match(x, /^[0-9]+:[0-9]{1,2}(\.[0-9]*)?$/)) { 192 split(x, hms, ":") 193 printf "%s = %12.4f s\n", x, 60*hms[1] + hms[2] 194 ok = 1 195 exit 0 196 } 197 198 # handle the hh:mm:ss time format 199 if (match(x, /^[0-9]+:[0-9]{1,2}:[0-9]{1,2}(\.[0-9]*)?$/)) { 200 split(x, hms, ":") 201 printf "%s = %12.4f s\n", x, 3600*hms[1] + 60*hms[2] + hms[3] 202 ok = 1 203 exit 0 204 } 205 206 # handle seconds, turning the number into the hh:mm:ss time format 207 if (unit == "s") { 208 h = (x - x % 3600) / 3600 209 m = (x % 3600) / 60 210 s = x % 60 211 printf "%s s = %02d:%02d:%05.2f\n", x, h, m, s 212 ok = 1 213 exit 0 214 } 215 } 216 217 # match the unit given to its built-in entry, if present 218 $1 == unit { 219 printf "%12.4f %s = %12.4f %s\n", x, $2, $3*x, $4 220 ok = 1 221 exit 0 222 } 223 224 # tell user when no match was found, and fail the whole surrounding tool if so 225 END { 226 if (!ok) { 227 fs = "\x1b[31munit name/alias `%s` not supported\n\x1b[0m" 228 printf fs, unit > "/dev/stderr" 229 exit 1 230 } 231 } 232 ' << 'EOF' 233 ac ac 4046.8564224 m² 234 acre ac 4046.8564224 m² 235 acres ac 4046.8564224 m² 236 angle deg 0.0174532925199 rad 237 andeg deg 0.0174532925199 rad 238 angdeg deg 0.0174532925199 rad 239 angular deg 0.0174532925199 rad 240 angulardeg deg 0.0174532925199 rad 241 angulardegree deg 0.0174532925199 rad 242 angulardegrees deg 0.0174532925199 rad 243 angledeg deg 0.0174532925199 rad 244 angledegree deg 0.0174532925199 rad 245 angledegrees deg 0.0174532925199 rad 246 barrel bbl 158.9873 L 247 barrels bbl 158.9873 L 248 bbl bbl 158.9873 L 249 cfeet ft³ 0.028316846592 m³ 250 cfoot ft³ 0.028316846592 m³ 251 cft ft³ 0.028316846592 m³ 252 cufeet ft³ 0.028316846592 m³ 253 cufoot ft³ 0.028316846592 m³ 254 cuft ft³ 0.028316846592 m³ 255 cup cup 0.23658824 L 256 cups cup 0.23658824 L 257 cyc tr 6.2831853071796 rad 258 cycle tr 6.2831853071796 rad 259 cycles tr 6.2831853071796 rad 260 d day 86400 s 261 day day 86400 s 262 days day 86400 s 263 deg deg 0.0174532925199 rad 264 degree deg 0.0174532925199 rad 265 degrees deg 0.0174532925199 rad 266 in in 2.54 cm 267 inch in 2.54 cm 268 inches in 2.54 cm 269 ft ft 0.3048 m 270 ft2 ft² 0.09290304 m² 271 ft3 ft³ 0.028316846592 m³ 272 ft² ft² 0.09290304 m² 273 ft³ ft³ 0.028316846592 m³ 274 feet ft 0.3048 m 275 feet2 ft² 0.09290304 m² 276 feet3 ft³ 0.028316846592 m³ 277 feet² ft² 0.09290304 m² 278 feet³ ft³ 0.028316846592 m³ 279 floz floz 29.5735295625 mL 280 foot ft 0.3048 m 281 foot2 ft² 0.09290304 m² 282 foot3 ft³ 0.028316846592 m³ 283 foot² ft² 0.09290304 m² 284 foot³ ft³ 0.028316846592 m³ 285 ga gal 3.785411784 L 286 gal gal 3.785411784 L 287 gallon gal 3.785411784 L 288 gallons gal 3.785411784 L 289 gb gb 1073741824 bytes 290 gib gb 1073741824 bytes 291 gon grad 0.0157079632679 rad 292 gons grad 0.0157079632679 rad 293 grad grad 0.0157079632679 rad 294 gradian grad 0.0157079632679 rad 295 gradians grad 0.0157079632679 rad 296 h hr 3600 s 297 hour hr 3600 s 298 hours hr 3600 s 299 hr hr 3600 s 300 hrs hr 3600 s 301 kb kb 1024 bytes 302 kib kb 1024 bytes 303 lb lb 0.45359237 kg 304 lbs lb 0.45359237 kg 305 mb mb 1048576 bytes 306 mi mi 1.609344 km 307 mib mb 1048576 bytes 308 mih mph 1.609344 kph 309 mi2 mi² 2.5899881103360 km² 310 mi² mi² 2.5899881103360 km² 311 mil mrad 0.001 rad 312 millirad mrad 0.001 rad 313 milliradian mrad 0.001 rad 314 milliradians mrad 0.001 rad 315 mile mi 1.609344 km 316 mile² mi² 2.5899881103360 km² 317 miles mi 1.609344 km 318 miles² mi² 2.5899881103360 km² 319 min min 60 s 320 minute min 60 s 321 minutes min 60 s 322 mpg mpg 0.425143707 kpl 323 mph mph 1.609344 kph 324 mrad mrad 0.001 rad 325 nmi nmi 1.852 km 326 nmile nmi 1.852 km 327 nmiles nmi 1.852 km 328 oilbarrel bbl 158.9873 L 329 oilbarrels bbl 158.9873 L 330 oz oz 28.349523125 g 331 ounce oz 28.349523125 g 332 ounces oz 28.349523125 g 333 pint pt 473.176473 mL 334 pla tr 6.2831853071796 rad 335 pound lb 0.45359237 kg 336 pounds lb 0.45359237 kg 337 psi psi 6894.757293168 Pa 338 pt pt 473.176473 mL 339 rad rad 57.295779513082 deg 340 radian rad 57.295779513082 deg 341 radians rad 57.295779513082 deg 342 rev tr 6.2831853071796 rad 343 revolution tr 6.2831853071796 rad 344 revolutions tr 6.2831853071796 rad 345 sfeet ft² 0.09290304 m² 346 sfoot ft² 0.09290304 m² 347 sft ft² 0.09290304 m² 348 smi mi² 2.5899881103360 km² 349 smile mi² 2.5899881103360 km² 350 smiles mi² 2.5899881103360 km² 351 syard yd² 0.83612736 m² 352 syards yd² 0.83612736 m² 353 syd yd² 0.83612736 m² 354 syds yd² 0.83612736 m² 355 sqfeet ft² 0.09290304 m² 356 sqfoot ft² 0.09290304 m² 357 sqft ft² 0.09290304 m² 358 sqmi mi² 2.5899881103360 km² 359 sqmile mi² 2.5899881103360 km² 360 sqmiles mi² 2.5899881103360 km² 361 sqyard yd² 0.83612736 m² 362 sqyards yd² 0.83612736 m² 363 sqyd yd² 0.83612736 m² 364 sqyds yd² 0.83612736 m² 365 tb tb 1099511627776 bytes 366 tib tb 1099511627776 bytes 367 ton ton 907.18474 kg 368 tr tr 6.2831853071796 rad 369 turn tr 6.2831853071796 rad 370 turns tr 6.2831853071796 rad 371 ukpint ukpt 568.26125 mL 372 ukpt ukpt 568.26125 mL 373 uspint pt 473.176473 mL 374 uspt pt 473.176473 mL 375 w wk 604800 s 376 week wk 604800 s 377 weeks wk 604800 s 378 wk wk 604800 s 379 wks wk 604800 s 380 yard yd 0.9144 m 381 yard2 yd² 0.83612736 m² 382 yards yd 0.9144 m 383 yards2 yd² 0.83612736 m² 384 yd yd 0.9144 m 385 yds yd 0.9144 m 386 yd² yd² 0.83612736 m² 387 yds² yd² 0.83612736 m² 388 EOF