Skip to main content

How to Format Numbers with Commas

• 2 min read
bash formatting numbers printf numfmt display

Quick Answer: Format Numbers with Commas in Bash

To format numbers with thousand separators, use printf "%'d\n" 1234567 which outputs 1,234,567. This requires locale support. For portability without locale, use sed or awk. The printf method is simplest when locale is available.

Quick Comparison: Number Formatting Methods

MethodSimplicityPortabilityBest ForRequirements
printf %‘dVery simpleGoodQuick formattingLocale support
numfmtSimpleLimitedLarge numbersGNU coreutils
sed/regexModerateExcellentPortable scriptsNone
awkModerateExcellentComplex processingNone

Bottom line: Use printf "%'d" for simplicity; use sed for portability.


Format large numbers with thousand separators for better readability. This guide covers using printf, numfmt, sed, and awk.

Method 1: Using printf with Locale (Simplest)

The simplest method using printf:

number=1234567
printf "%'d\n" "$number"

# Output: 1,234,567

Note: The ' flag adds locale-aware thousands separators.

Using numfmt (GNU Tool)

The dedicated tool for number formatting:

number=1234567
numfmt --to=iec --grouping "$number"

# Output: 1,234,567

Using sed to Add Commas

A regex-based approach:

number=1234567

# Add commas from right to left
echo "$number" | sed ':a;s/\B[0-9]\{3\}\>/,&/g;ta'

# Output: 1,234,567

Function for Number Formatting

#!/bin/bash

format_number() {
  local number=$1

  # Using printf
  printf "%'d\n" "$number"
}

# Usage
format_number 1000
format_number 1234567
format_number 999

Output:

1,000
1,234,567
999

Format Decimal Numbers

#!/bin/bash

format_decimal() {
  local number=$1
  local decimals=${2:-2}

  # Format with decimals and comma separator
  printf "%'.${decimals}f\n" "$number"
}

# Usage
format_decimal 1234567.891 2
format_decimal 1000.5 1

Output:

1,234,567.89
1,000.5

Format Different Locales

#!/bin/bash

number=1234567

# US format (comma)
export LC_NUMERIC=en_US.UTF-8
echo "US: $(printf "%'d\n" $number)"

# European format (dot)
export LC_NUMERIC=de_DE.UTF-8
echo "German: $(printf "%'d\n" $number)"

# European with comma (thousands)
export LC_NUMERIC=fr_FR.UTF-8
echo "French: $(printf "%'d\n" $number)"

Output:

US: 1,234,567
German: 1.234.567
French: 1 234 567

Practical Example: Currency Formatting

#!/bin/bash

format_currency() {
  local amount=$1
  local currency="${2:-USD}"

  # Format with 2 decimals and comma separator
  formatted=$(printf "%'.2f\n" "$amount")

  case "$currency" in
    USD)
      echo "\$$formatted"
      ;;
    EUR)
      echo "€$formatted"
      ;;
    GBP)
      echo "£$formatted"
      ;;
    *)
      echo "$formatted $currency"
      ;;
  esac
}

# Usage
format_currency 1234567.89 USD
format_currency 1234567.89 EUR
format_currency 1234567.89 GBP

Output:

$1,234,567.89
€1,234,567.89
£1,234,567.89

Format from File

#!/bin/bash

# File: format_numbers.sh

input_file="$1"

if [ ! -f "$input_file" ]; then
  echo "Usage: $0 <input_file>"
  exit 1
fi

while read number; do
  # Skip empty lines
  [ -z "$number" ] && continue

  # Format and output
  formatted=$(printf "%'d\n" "$number" 2>/dev/null || echo "$number")
  echo "$formatted"
done < "$input_file"

Test file (numbers.txt):

1000
1234567
999
500000

Usage:

$ chmod +x format_numbers.sh
$ ./format_numbers.sh numbers.txt

Output:

1,000
1,234,567
999
500,000

Format in Calculations

#!/bin/bash

# Calculate and format result

sales=1234567
returns=123456
profit=$((sales - returns))

echo "Sales:   $(printf "%'d\n" $sales)"
echo "Returns: $(printf "%'d\n" $returns)"
echo "Profit:  $(printf "%'d\n" $profit)"

Output:

Sales:   1,234,567
Returns: 123,456
Profit:  1,111,111

Format Large Numbers with Abbreviation

#!/bin/bash

format_bytes() {
  local bytes=$1

  if [ "$bytes" -lt 1024 ]; then
    echo "${bytes}B"
  elif [ "$bytes" -lt 1048576 ]; then
    echo "$(printf "%.2f" $((bytes * 100 / 1024)) | xargs -I {} echo "scale=2; {} / 100" | bc)KB"
  elif [ "$bytes" -lt 1073741824 ]; then
    echo "$(printf "%.2f" $((bytes * 100 / 1048576)) | xargs -I {} echo "scale=2; {} / 100" | bc)MB"
  else
    echo "$(printf "%.2f" $((bytes * 100 / 1073741824)) | xargs -I {} echo "scale=2; {} / 100" | bc)GB"
  fi
}

# Usage
format_bytes 512
format_bytes 1048576
format_bytes 1073741824

Format in Column Output

#!/bin/bash

# File: sales_report.sh

data_file="$1"

if [ ! -f "$data_file" ]; then
  echo "Usage: $0 <data_file>"
  exit 1
fi

# Print header
printf "%-15s %15s %15s\n" "Product" "Revenue" "Profit"
printf "%-15s %15s %15s\n" "-------" "--------" "------"

# Print formatted rows
while IFS=',' read product revenue profit; do
  printf "%-15s %15s %15s\n" \
    "$product" \
    "$(printf "%'d" "$revenue")" \
    "$(printf "%'d" "$profit")"
done < "$data_file"

Test file (sales.csv):

Apple,1234567,567890
Banana,987654,123456
Cherry,456789,89012

Output:

Product               Revenue            Profit
-------               --------            ------
Apple              1,234,567           567,890
Banana               987,654           123,456
Cherry               456,789            89,012

Format with Padding

#!/bin/bash

# Format numbers with fixed width and right alignment

numbers=(100 1000 10000 100000 1000000)

for num in "${numbers[@]}"; do
  # Right-aligned in 12-character field
  printf "%12'd\n" "$num"
done

Output:

         100
       1,000
      10,000
     100,000
   1,000,000

Using awk for Formatting

# Format using awk
awk '{printf "%'"'"'d\n", $1}' numbers.txt

# Format with conditions
awk '$1 > 1000 {printf "%'"'"'d\n", $1}' numbers.txt

Performance Comparison

MethodSpeedCompatibilityBest For
printfFastGoodSimple formatting
numfmtFastGNU onlyStandard tool
sedSlowExcellentPortable
awkMediumGoodBatch processing

Common Mistakes

  1. Not escaping the quote in printf - use %'d with single quote
  2. Locale not set - export LC_NUMERIC for consistent output
  3. Losing precision - use %'f for floating point
  4. Not handling negative numbers - printf handles them correctly
  5. Expecting all systems have numfmt - it’s GNU-only

Quick Reference

# Integer with commas
printf "%'d\n" 1234567         # 1,234,567

# Decimal with commas
printf "%'.2f\n" 1234567.89    # 1,234,567.89

# Right-aligned, padded
printf "%15'd\n" 1234567       #    1,234,567

# Using numfmt
numfmt --grouping 1234567      # 1,234,567

Key Points

  • Use printf "%'d" for simplest solution
  • Check LC_NUMERIC locale setting
  • Use numfmt for standard tool approach
  • sed works everywhere but is slower
  • Test with negative numbers and decimals

Summary

Number formatting improves readability in reports and output. Use printf’s %'d flag for the simplest solution, numfmt for standard tools, or sed for maximum portability.