File: bu.sh 1 #!/bin/sh 2 3 # The MIT License (MIT) 4 # 5 # Copyright © 2020-2025 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() { bu "$@" | awk '{ print $(NF-1), $NF }'; } 52 53 54 # handle help options 55 case "$1" in 56 -h|--h|-help|--help) 57 awk '/^# +bu /, /^$/ { gsub(/^# ?/, ""); print }' "$0" 58 exit 0 59 ;; 60 esac 61 62 if [ -z "$1" ]; then 63 awk '/^# +bu /, /^$/ { gsub(/^# ?/, ""); print }' "$0" 64 exit 0 65 fi 66 67 # normalize the unit name right away, to avoid re-running the same apps 68 unitname="$(echo "${2}" | tr "[:upper:]" "[:lower:]" | tr -d - | tr -d _)" 69 70 case "${unitname}" in 71 # handle that mixed-unit abomination using feet and inches 72 ft|feet|foot) 73 case "$(echo "${4}" | tr "[:upper:]" "[:lower:]")" in 74 in|inch|inches) 75 y=$(echo "scale=4; 0.3048*${1} + 0.0254*${3}" | bc) 76 printf "%12.4f ft %12.4f in = %12.4f m\n" \ 77 "${1}" "${3}" "${y}" 78 exit $? 79 ;; 80 esac 81 ;; 82 83 # handle hertz, megahertz, and gigahertz: even some old-fashioned names 84 # are supported; the name `cycle` is handled as an angular unit instead 85 hz|hertz) 86 y=$(echo "scale=4; 1/${1}" | bc) 87 printf "%12.4f hz = %12.4f s\n" "${1}" "${y}" 88 exit $? 89 ;; 90 mhz|megahertz|megacycle|megacycles) 91 y=$(echo "scale=12; 1/(1000000*${1})" | bc) 92 printf "%12.4f hz = %12.12f s\n" "${1}" "${y}" 93 exit $? 94 ;; 95 ghz|gigahertz|gigacycle|gigacycles) 96 y=$(echo "scale=12; 1/(1000000000*${1})" | bc) 97 printf "%12.4f hz = %12.12f s\n" "${1}" "${y}" 98 exit $? 99 ;; 100 101 # handle that mixed-unit abomination using pounds and weight-ounces 102 lb|lbs|pound|pounds) 103 case "$(echo "${4}" | tr "[:upper:]" "[:lower:]")" in 104 oz|ozs|ounce|ounces) 105 y=$(echo "scale=4; 0.45359237*${1} + 0.028349523*${3}" | bc) 106 printf "%12.4f lb %12.4f oz = %12.4f kg\n" \ 107 "${1}" "${3}" "${y}" 108 exit $? 109 ;; 110 esac 111 ;; 112 113 # handle converting numbers from base 2 into base-10 ones 114 bin|binary|base2|b2|0b|bit|bits|2) 115 # check for valid binary values, quitting whole script on failure 116 if echo "$1" | grep -E -q '.*[^01].*'; then 117 printf "\e[31minvalid binary number %s\e[0m\n" "$1" > /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 "\e[31minvalid octal number %s\e[0m\n" "$1" > /dev/stderr 131 exit 1 132 fi 133 134 decval=$(echo "ibase=8; ${1}" | bc) 135 printf "%s oct = %s dec\n" "${1}" "${decval}" 136 exit $? 137 ;; 138 139 # handle converting numbers from base 16 into base-10 ones 140 hex|hexa|hexadec|hexadecimal|base16|b16|0x|x|16) 141 hexval=$(echo "${1}" | sed 's-^0x--' | tr '[:lower:]' '[:upper:]') 142 if echo "${hexval}" | grep -E -q '.*[^0-9a-fA-F].*'; then 143 printf "\e[31minvalid octal number %s\e[0m\n" "$1" > /dev/stderr 144 exit 1 145 fi 146 147 decval=$(echo "ibase=16; ${hexval}" | bc) 148 printf "%s hex = %s dec\n" "${hexval}" "${decval}" 149 exit $? 150 ;; 151 esac 152 153 # warn users who might wrongly think multiple pairs of args are allowed 154 # in general: only ft/in and lb/oz are allowed 155 if [ $# -gt 2 ]; then 156 printf "\e[31m only 1 or 2 args allowed, unless using ft/in or " >&2 157 printf "lb/oz mixed-units value-pairs\e[0m\n" >&2 158 exit 1 159 fi 160 161 # handle all other unit-conversions 162 awk -v x="${1:-0}" -v unit="${unitname}" ' 163 # normalize both quantities and units, and handle special cases for units 164 BEGIN { 165 # ignore underscores in numbers, thus `allowing` them for convenience 166 gsub(/[_]/, "", x) 167 168 if (x + 0 == 0 && x !~ /0+/) { 169 fs = "\x1b[31mvalue `%s` not a valid number\n\x1b[0m" 170 printf fs, unit > "/dev/stderr" 171 good_unit = 1 172 exit 1 173 } 174 175 # normalize unit names for later lookup 176 unit = tolower(unit) 177 gsub(/[ _.-]/, "", unit) 178 179 # handle fahrenheit temperatures 180 if (unit == "f" || unit == "fahrenheit") { 181 printf "%12.4f °F = %12.4f °C\n", x, (x - 32) * (5.0/9.0) 182 good_unit = 1 183 exit 0 184 } 185 186 # handle kelvin temperatures 187 if (unit == "k" || unit == "kelvin") { 188 printf "%12.4f °K = %12.4f °C\n", x, x - 273.15 189 good_unit = 1 190 exit 0 191 } 192 193 # handle the mm:ss time format 194 if (match(x, /^[0-9]+:[0-9]{1,2}(\.[0-9]*)?$/)) { 195 split(x, hms, ":") 196 printf "%s = %12.4f s\n", x, 60*hms[1] + hms[2] 197 good_unit = 1 198 exit 0 199 } 200 201 # handle the hh:mm:ss time format 202 if (match(x, /^[0-9]+:[0-9]{1,2}:[0-9]{1,2}(\.[0-9]*)?$/)) { 203 split(x, hms, ":") 204 printf "%s = %12.4f s\n", x, 3600*hms[1] + 60*hms[2] + hms[3] 205 good_unit = 1 206 exit 0 207 } 208 209 # handle seconds, turning the number into the hh:mm:ss time format 210 if (unit == "s") { 211 h = (x - x % 3600) / 3600 212 m = (x % 3600) / 60 213 s = x % 60 214 printf "%s s = %02d:%02d:%05.2f\n", x, h, m, s 215 good_unit = 1 216 exit 0 217 } 218 } 219 220 # match the unit given to its built-in entry, if present 221 $1 == unit { 222 printf "%12.4f %s = %12.4f %s\n", x, $2, $3*x, $4 223 good_unit = 1 224 exit 0 225 } 226 227 # tell user when no match was found, and fail the whole surrounding tool if so 228 END { 229 if (!good_unit) { 230 fs = "\x1b[31munit name/alias `%s` not supported\n\x1b[0m" 231 printf fs, unit > "/dev/stderr" 232 exit 1 233 } 234 } 235 ' << 'EOF' 236 ac ac 4046.8564224 m² 237 acre ac 4046.8564224 m² 238 acres ac 4046.8564224 m² 239 angle deg 0.0174532925199 rad 240 andeg deg 0.0174532925199 rad 241 angdeg deg 0.0174532925199 rad 242 angular deg 0.0174532925199 rad 243 angulardeg deg 0.0174532925199 rad 244 angulardegree deg 0.0174532925199 rad 245 angulardegrees deg 0.0174532925199 rad 246 angledeg deg 0.0174532925199 rad 247 angledegree deg 0.0174532925199 rad 248 angledegrees deg 0.0174532925199 rad 249 barrel bbl 158.9873 L 250 barrels bbl 158.9873 L 251 bbl bbl 158.9873 L 252 cfeet ft³ 0.028316846592 m³ 253 cfoot ft³ 0.028316846592 m³ 254 cft ft³ 0.028316846592 m³ 255 cufeet ft³ 0.028316846592 m³ 256 cufoot ft³ 0.028316846592 m³ 257 cuft ft³ 0.028316846592 m³ 258 cup cup 0.23658824 L 259 cups cup 0.23658824 L 260 cyc tr 6.2831853071796 rad 261 cycle tr 6.2831853071796 rad 262 cycles tr 6.2831853071796 rad 263 d day 86400 s 264 day day 86400 s 265 days day 86400 s 266 deg deg 0.0174532925199 rad 267 degree deg 0.0174532925199 rad 268 degrees deg 0.0174532925199 rad 269 in in 2.54 cm 270 inch in 2.54 cm 271 inches in 2.54 cm 272 ft ft 0.3048 m 273 ft2 ft² 0.09290304 m² 274 ft3 ft³ 0.028316846592 m³ 275 ft² ft² 0.09290304 m² 276 ft³ ft³ 0.028316846592 m³ 277 feet ft 0.3048 m 278 feet2 ft² 0.09290304 m² 279 feet3 ft³ 0.028316846592 m³ 280 feet² ft² 0.09290304 m² 281 feet³ ft³ 0.028316846592 m³ 282 floz floz 29.5735295625 mL 283 foot ft 0.3048 m 284 foot2 ft² 0.09290304 m² 285 foot3 ft³ 0.028316846592 m³ 286 foot² ft² 0.09290304 m² 287 foot³ ft³ 0.028316846592 m³ 288 ga gal 3.785411784 L 289 gal gal 3.785411784 L 290 gallon gal 3.785411784 L 291 gallons gal 3.785411784 L 292 gb gb 1073741824 bytes 293 gib gb 1073741824 bytes 294 gon grad 0.0157079632679 rad 295 gons grad 0.0157079632679 rad 296 grad grad 0.0157079632679 rad 297 gradian grad 0.0157079632679 rad 298 gradians grad 0.0157079632679 rad 299 h hr 3600 s 300 hour hr 3600 s 301 hours hr 3600 s 302 hr hr 3600 s 303 hrs hr 3600 s 304 kb kb 1024 bytes 305 kib kb 1024 bytes 306 lb lb 0.45359237 kg 307 lbs lb 0.45359237 kg 308 mb mb 1048576 bytes 309 mi mi 1.609344 km 310 mib mb 1048576 bytes 311 mih mph 1.609344 kph 312 mi2 mi² 2.5899881103360 km² 313 mi² mi² 2.5899881103360 km² 314 mil mrad 0.001 rad 315 millirad mrad 0.001 rad 316 milliradian mrad 0.001 rad 317 milliradians mrad 0.001 rad 318 mile mi 1.609344 km 319 mile² mi² 2.5899881103360 km² 320 miles mi 1.609344 km 321 miles² mi² 2.5899881103360 km² 322 min min 60 s 323 minute min 60 s 324 minutes min 60 s 325 mpg mpg 0.425143707 kpl 326 mph mph 1.609344 kph 327 mrad mrad 0.001 rad 328 nmi nmi 1.852 km 329 nmile nmi 1.852 km 330 nmiles nmi 1.852 km 331 oilbarrel bbl 158.9873 L 332 oilbarrels bbl 158.9873 L 333 oz oz 28.349523125 g 334 ounce oz 28.349523125 g 335 ounces oz 28.349523125 g 336 pint pt 473.176473 mL 337 pla tr 6.2831853071796 rad 338 pound lb 0.45359237 kg 339 pounds lb 0.45359237 kg 340 psi psi 6894.757293168 Pa 341 pt pt 473.176473 mL 342 rad rad 57.295779513082 deg 343 radian rad 57.295779513082 deg 344 radians rad 57.295779513082 deg 345 rev tr 6.2831853071796 rad 346 revolution tr 6.2831853071796 rad 347 revolutions tr 6.2831853071796 rad 348 sfeet ft² 0.09290304 m² 349 sfoot ft² 0.09290304 m² 350 sft ft² 0.09290304 m² 351 smi mi² 2.5899881103360 km² 352 smile mi² 2.5899881103360 km² 353 smiles mi² 2.5899881103360 km² 354 syard yd² 0.83612736 m² 355 syards yd² 0.83612736 m² 356 syd yd² 0.83612736 m² 357 syds yd² 0.83612736 m² 358 sqfeet ft² 0.09290304 m² 359 sqfoot ft² 0.09290304 m² 360 sqft ft² 0.09290304 m² 361 sqmi mi² 2.5899881103360 km² 362 sqmile mi² 2.5899881103360 km² 363 sqmiles mi² 2.5899881103360 km² 364 sqyard yd² 0.83612736 m² 365 sqyards yd² 0.83612736 m² 366 sqyd yd² 0.83612736 m² 367 sqyds yd² 0.83612736 m² 368 tb tb 1099511627776 bytes 369 tib tb 1099511627776 bytes 370 ton ton 907.18474 kg 371 tr tr 6.2831853071796 rad 372 turn tr 6.2831853071796 rad 373 turns tr 6.2831853071796 rad 374 ukpint ukpt 568.26125 mL 375 ukpt ukpt 568.26125 mL 376 uspint pt 473.176473 mL 377 uspt pt 473.176473 mL 378 w wk 604800 s 379 week wk 604800 s 380 weeks wk 604800 s 381 wk wk 604800 s 382 wks wk 604800 s 383 yard yd 0.9144 m 384 yard2 yd² 0.83612736 m² 385 yards yd 0.9144 m 386 yards2 yd² 0.83612736 m² 387 yd yd 0.9144 m 388 yds yd 0.9144 m 389 yd² yd² 0.83612736 m² 390 yds² yd² 0.83612736 m² 391 EOF