Linux Basics: Format and Parse Size Values with GNU numfmt
A report containing 5242880 is exact but not always easy to scan. GNU numfmt can render numbers with readable units, parse unit-suffixed values, and convert one field without rewriting the surrounding labels. Keep the raw values for calculations and format a separate view for readers.
These examples were tested on Linux with GNU Bash 5.2.37 and GNU coreutils 9.7. Use Bash rather than sh. The commands operate only on the small practice inputs shown here.
Prepare a scratch directory
You need GNU numfmt, Bash, a text editor, and the mktemp, rm, and rmdir utilities. Keep using the same terminal. Save each named source file in this new directory, then run it once in the order shown. Invoking bash explicitly avoids changing executable permissions. No administrator access is needed.
start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 11. Compare decimal and binary display
Save this as numfmt-display.sh:
#!/usr/bin/env bash
set -eu
export LC_ALL=C
printf 'Decimal: '
numfmt --to=si --format='%.2f' 1536
printf 'Binary: '
numfmt --to=iec-i --format='%.2f' 1536Run it:
bash numfmt-display.shOutput:
Decimal: 1.54k
Binary: 1.50KiThe same value, 1536, is displayed with two different scaling conventions. SI uses steps of 1000 and the binary iec-i mode uses steps of 1024 with explicit Ki-style suffixes. The format asks for two decimal places.
The decimal result is rounded, while 1536 divided by 1024 is exactly 1.5. The command is formatting numbers, not detecting whether they represent bytes, seconds, or something else. This tutorial treats the input values as byte counts.
2. Parse explicit unit suffixes
Save this as numfmt-parse.sh:
#!/usr/bin/env bash
set -eu
export LC_ALL=C
numfmt --from=auto 3K 3Ki 1.5MiRun it:
bash numfmt-parse.shOutput:
3000
3072
1572864The three outputs correspond to the three arguments in order. With --from=auto, 3K means 3000, 3Ki means 3072, and 1.5Mi means 1572864. That difference matters when a configuration value or a limit is supplied by a person.
Choose the parsing convention deliberately rather than assuming every tool uses the same meaning for K. In particular, --from=iec would interpret a single-letter K differently from the auto mode used here.
3. Convert only a report column
Save this as numfmt-column.sh:
#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
printf '%s\n' 'name|size' 'report|2048' 'archive|5242880' |
numfmt --delimiter='|' --field=2 --header=1 --to=iec-iRun it:
bash numfmt-column.shOutput:
name|size
report|2.0Ki
archive|5.0MiThe input contains a header and two simple pipe-delimited rows. --field=2 changes only the second field, while --header=1 leaves the first line untouched. The record labels stay in place, making the result suitable for a small readable report.
The pipe character is passed as data because it is quoted in the option. This is delimiter-based field processing, not a full CSV parser: quoted delimiters or embedded records require a format-aware tool instead.
Keep in mind
The scripts set LC_ALL=C for predictable decimal punctuation. Human-readable values can lose precision through rounding, so retain original counts instead of converting a rounded display back into authoritative data. GNU numfmt defaults to rounding away from zero when scaling; use an explicit rounding mode when that choice matters.
Invalid input normally stops conversion with a nonzero status. Do not silently switch to --invalid=ignore in a validation pipeline: that mode can return success with unconverted input still present. The examples use Bash’s pipefail where a pipeline should fail if either stage fails.
Clean up
In the same terminal, remove only the named practice files, return to your original directory, and remove the now-empty scratch directory:
rm -- numfmt-display.sh numfmt-parse.sh numfmt-column.sh
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dirReferences
Acknowledgements
This post was created with assistance from AI.