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