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