Last active
August 3, 2026 18:09
-
-
Save ernstki/8cde67c2593d10cd6e24f771f09fd5a9 to your computer and use it in GitHub Desktop.
Convert human-readable figures to/from byte sizes using AWK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/awk -f | |
| ## | |
| ## Author: Kevin Ernst <ernstki -at- mail.uc.edu | |
| ## Homepage: https://gist.github.com/ernstki/8cde67c2593d10cd6e24f771f09fd5a9 | |
| ## License: Zero-Clause BSD (basically public domain) | |
| ## | |
| ## Notes: Library functions themselves should work with any AWK, but the | |
| ## self-tests in the `END` block will only run with Gawk, because | |
| ## they're using the three-argument `match` which is GNU-only | |
| ## | |
| function humansize(b) { | |
| if (b < 1024) return b | |
| else if (b < 1024^2) return sprintf("%0.1fK", b/1024) | |
| else if (b < 1024^3) return sprintf("%0.1fM", b/1024^2) | |
| else if (b < 1024^4) return sprintf("%0.1fG", b/1024^3) | |
| else if (b < 1024^5) return sprintf("%0.1fT", b/1024^4) | |
| else return sprintf("%0.1fP", b/1024^5) | |
| } | |
| function dehumansize(s, u, n, i) { | |
| gsub(/[[:space:]]/, "", s) # strip whitespace | |
| if (index(s, "B") == 0) { # if no "B" at the end | |
| u = substr(s, length(s)) | |
| n = substr(s, 1, length(s)-1) | |
| } else { | |
| u = substr(s, length(s)-1, 1) | |
| n = substr(s, 1, length(s)-2) | |
| } | |
| i = index("kmgte", tolower(u)) | |
| #print s, u, n, i > "/dev/stderr" | |
| return i ? sprintf("%0d", n * 1024^i) : s | |
| } | |
| END { | |
| trials["humansize(1001)"] = "1001" | |
| trials["humansize(1024)"] = "1.0K" | |
| trials["humansize(1200)"] = "1.2K" | |
| trials["humansize(2048)"] = "2.0K" | |
| trials["humansize(10485760)"] = "10.0M" | |
| trials["humansize(92274688)"] = "88.0M" | |
| trials["humansize(13304090696090)"] = "12.1T" | |
| trials["dehumansize(1001)"] = 1001 | |
| trials["dehumansize(1k)"] = 1024 | |
| trials["dehumansize(1K)"] = 1024 | |
| trials["dehumansize(1G)"] = 1073741824 | |
| trials["dehumansize(13.7G)"] = 14710262989 | |
| trials["dehumansize(88M)"] = 92274688 | |
| trials["dehumansize(12.1T)"] = 13304090696090 | |
| passed = failed = 0 | |
| eps = 1e-10 # accommodate very small deviations in FP precision | |
| for (trial in trials) { | |
| expected = trials[trial] | |
| # Gawk only, because standard AWK is a pain here | |
| if (match(trial, /^humansize\(([^)]+)\)/, arr)) | |
| actual = humansize(arr[1]) | |
| if (match(trial, /dehumansize\(([^)]+)\)/, arr)) | |
| actual = dehumansize(arr[1]) | |
| delta = (actual > expected) ? actual - expected : expected - actual | |
| if (delta < eps * actual) { | |
| printf " \033[32m✔\033[0m Passed: %s == %s\n", trial, expected | |
| passed++ | |
| } else { | |
| printf " \033[31m✘\033[0m Failed: Expected %s == %s, got %s\n", \ | |
| trial, expected, actual | |
| failed++ | |
| } | |
| } | |
| printf "\nTotal: %d | \033[32mPassed: %d\033[0m | " \ | |
| "\033[31mFailed: %d\033[0m\n\n", passed + failed, passed, failed | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment