Skip to content

Instantly share code, notes, and snippets.

@antiops
Forked from agunnerson-ibm/human_readable.sh
Last active May 22, 2024 07:36
Show Gist options
  • Save antiops/19715bcbd3816d0906a40348a67db65d to your computer and use it in GitHub Desktop.
Save antiops/19715bcbd3816d0906a40348a67db65d to your computer and use it in GitHub Desktop.
Bash function to convert bytes to human readable size
# Copyright 2015 Andrew Gunnerson <[email protected]>
# Copyright 2024 antiops@github
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Convert bytes to human readable size
# $1: Size in bytes
# $2: Floating point precision (digits after dot)
# Return: Nothing
# Prints: Human readable size
#
# Example: "$(human_readable 6390759424 2)" == "5.95 GiB"
human_readable() {
local abbrevs=(
$((1 << 60)):ZiB
$((1 << 50)):EiB
$((1 << 40)):TiB
$((1 << 30)):GiB
$((1 << 20)):MiB
$((1 << 10)):KiB
$((1)):Bytes
)
local no_input=$([[ -z "$1" ]] && echo " (No Input)")
local bytes=$((10#${1:-0}))
local precision=$((10#${2:-2}))
if [[ "${bytes}" == "0" ]]; then
echo "0 Bytes$no_input"
elif [[ "${bytes}" == "1" ]]; then
echo "1 Byte"
else
for item in "${abbrevs[@]}"; do
local factor="${item%:*}"
local abbrev="${item#*:}"
if [[ "${bytes}" -ge "${factor}" ]]; then
local size="$(bc -l <<< "${bytes} / ${factor}")"
local size_floating="$(printf "%.*f" "${precision}" "${size}")"
printf "%g %s\n" "${size_floating}" "${abbrev}"
break
fi
done
fi
}
@antiops
Copy link
Author

antiops commented May 22, 2024

Changelog

  • Set default values to input variables

    • Bytes: 0
    • Precision: 2
  • Handle strings bash would percieve as octals 1

$ human_readable 09999999
9.54 MiB
  • Handle 0 or no input
$ human_readable 0
0 Bytes

$ human_readable
0 Bytes (No Input)
  • Normalize floating point to decimal after precision application (ie 5.00000001 -> 5.00 -> 5) 2 3
$ human_readable 5
5 Bytes

Footnotes

  1. StackOverflow: Convert string into integer in bash script

  2. StackOverflow: Use printf to format floats without decimal places if only trailing 0s

  3. Python 3 Documentation: string Format Specification

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment