|

Linux CLI 67 ๐Ÿง Number bases and conversion

#!/bin/bash

octal_value="32"
decimal=$(( 0$octal_value ))
echo $decimal

hex_value="1A"
decimal=$(( 0x$hex_value ))
echo $decimal

binary_value="11010"
decimal=$(( 2#$binary_value ))
echo $decimal

decimal=26
octal=$(printf "%o\n" $decimal)
echo $octal

hex=$(printf "%x\n" $decimal)
echo $hex

binary=$(echo "obase=2; $decimal" | bc)
echo $binary

Bash arithmetic works in decimal by default, but it can handle octal, hexadecimal, and binary too. Converting between bases is a common task โ€” file permissions, memory addresses, bitmasks, and color codes all use non-decimal bases at some point.

Key point: Bash’s arithmetic $((...)) can read numbers in any base using prefixes (0 for octal, 0x for hex, base#number for anything). To write numbers in another base, you need printf (for octal and hex) or bc (for binary).


a – Number bases in shell scripts

You can use variables with different bases by prefixing them:

PrefixBaseExample
0xHexadecimal (16)0x1A = 26
0Octal (8)025 = 21
0bBinary (2)0b1010 = 10
num_hex=0x1A       # hexadecimal
num_oct=025        # octal
num_bin=0b1010     # binary

How bash interprets these:

$ echo $(( 0x1A ))
[ 26 ]

$ echo $(( 025 ))
[ 21 ]

$ echo $(( 0b1010 ))
[ 10 ]

But there’s a catch with variables.

The leading-zero problem:

When you store a number in a variable as a string, the prefix is just part of the string. Bash won’t interpret it unless you tell it to.

$ num=025
$ echo $num
[ 025 ]

$ echo $(( num ))
[ 25 ]              # โŒ interpreted as decimal 25, not octal 21

Bash saw 025 and treated it as plain decimal 25. To force octal interpretation, add the 0 prefix inside the arithmetic expression:

$ num=25
$ echo $(( 0$num ))
[ 21 ]              # โœ… octal 25 = decimal 21

Or store the value without a leading zero and add it back when converting:

$ octal_value="32"
$ echo $(( 0$octal_value ))
[ 26 ]              # octal 32 = decimal 26

Hex works similarly:

$ hex_value="1A"
$ echo $(( 0x$hex_value ))
[ 26 ]              # hex 1A = decimal 26

The 0x prefix is added inside $(( )), so bash recognizes the value as hexadecimal.

Binary needs a different form:

Binary can’t use a simple prefix inside $(( )) the way octal and hex do. Use the base#number syntax:

$ binary_value="11010"
$ echo $(( 2#$binary_value ))
[ 26 ]              # binary 11010 = decimal 26

The general form is base#number, where base is 2โ€“64:

ExpressionMeaningDecimal
2#11010Binary26
8#32Octal26
16#1AHex26
10#25Decimal25
36#ZBase 3635
$ echo $(( 2#11010 ))
[ 26 ]
$ echo $(( 8#32 ))
[ 26 ]
$ echo $(( 16#1A ))
[ 26 ]
$ echo $(( 36#Z ))
[ 35 ]

Important gotchas:

  • If you try to convert a string like 0x1G with $(( 0x$var )), bash throws an error โ€” G isn’t a valid hex digit:
$ var="1G"
$ echo $(( 0x$var ))
[ bash: 0x1G: value too great for base ]
  • Hexadecimal is case-insensitive: 1a == 1A.
  • Octal and binary use only digits โ€” no letters allowed.
  • Leading zeros in decimal literals can silently turn them into octal. Always use 10# to force decimal:
$ echo $(( 010 ))
[ 8 ]                # โŒ octal!
$ echo $(( 10#010 ))
[ 10 ]               # โœ… decimal

This is a classic bug โ€” 08 and 09 will fail because they aren’t valid octal digits:

$ echo $(( 08 ))
[ bash: 08: value too great for base (error token is "08") ]

$ echo $(( 10#08 ))
[ 8 ]

Rule of thumb: When converting a user-provided or file-read number that might have a leading zero, always prefix with 10# unless you specifically want octal.


b – Base conversions in shell scripts

Conversion goes two ways: from another base into decimal, and from decimal into another base.

Converting from another base to decimal:

Bash’s $((...)) handles this directly with the right prefix:

FromSyntaxExampleResult
Octal$(( 0$var ))$(( 032 ))26
Hex$(( 0x$var ))$(( 0x1A ))26
Binary$(( 2#$var ))$(( 2#11010 ))26
Any base$(( base#$var ))$(( 36#Z ))35
# Octal to decimal
$ octal_value="32"
$ decimal=$(( 0$octal_value ))
$ echo $decimal
[ 26 ]

# Hexadecimal to decimal
$ hex_value="1A"
$ decimal=$(( 0x$hex_value ))
$ echo $decimal
[ 26 ]

# Binary to decimal
$ binary_value="11010"
$ decimal=$(( 2#$binary_value ))
$ echo $decimal
[ 26 ]

Converting from decimal to another base:

Bash can’t do this directly inside $(( )) โ€” it always produces decimal output. You need printf or bc.

Decimal to octal โ€” printf "%o":

$ decimal=26
$ octal=$(printf "%o\n" $decimal)
$ echo $octal
[ 32 ]

%o formats an integer as octal.

Decimal to hexadecimal โ€” printf "%x":

$ decimal=26
$ hex=$(printf "%x\n" $decimal)
$ echo $hex
[ 1a ]

%x formats as lowercase hex; %X gives uppercase:

$ printf "%x\n" 26
[ 1a ]
$ printf "%X\n" 26
[ 1A ]

Decimal to binary โ€” bc:

Bash has no built-in way to output binary. Use bc with obase (output base):

$ decimal=26
$ binary=$(echo "obase=2; $decimal" | bc)
$ echo $binary
[ 11010 ]

More printf base specifiers:

FormatMeaningExample
%dDecimalprintf "%d\n" 26 โ†’ 26
%oOctalprintf "%o\n" 26 โ†’ 32
%xHex (lower)printf "%x\n" 26 โ†’ 1a
%XHex (upper)printf "%X\n" 26 โ†’ 1A
%#oOctal with 0 prefixprintf "%#o\n" 26 โ†’ 032
%#xHex with 0x prefixprintf "%#x\n" 26 โ†’ 0x1a
%#XHex with 0X prefixprintf "%#X\n" 26 โ†’ 0X1A
$ printf "%o\n" 26
[ 32 ]
$ printf "%x\n" 26
[ 1a ]
$ printf "%X\n" 26
[ 1A ]
$ printf "%#o\n" 26
[ 032 ]
$ printf "%#x\n" 26
[ 0x1a ]

Using bc for any base:

bc can output in any base from 2 to 16 (and beyond with some limitations):

# Decimal to binary
$ echo "obase=2; 26" | bc
[ 11010 ]

# Decimal to octal
$ echo "obase=8; 26" | bc
[ 32 ]

# Decimal to hex
$ echo "obase=16; 26" | bc
[ 1A ]

# Convert back: binary to decimal
$ echo "ibase=2; 11010" | bc
[ 26 ]

# Hex to decimal
$ echo "ibase=16; 1A" | bc
[ 26 ]
  • obase=N sets the output base
  • ibase=N sets the input base

โš ๏ธ Warning: With bc, set ibase before obase when converting โ€” once ibase changes, the number you pass to obase is interpreted in the new base. For most simple cases you only set one at a time, so it’s fine.

# Convert from hex to binary in one go
$ echo "ibase=16; obase=2; 1A" | bc
[ 11010 ]

# Convert from binary to hex
$ echo "ibase=2; obase=16; 11010" | bc
[ 1A ]

A complete conversion table:

FromToCommand
OctalDecimal$(( 0$var ))
HexDecimal$(( 0x$var ))
BinaryDecimal$(( 2#$var ))
DecimalOctalprintf "%o\n" $dec
DecimalHexprintf "%x\n" $dec
DecimalBinaryecho "obase=2; $dec" | bc
HexBinaryecho "ibase=16; obase=2; $hex" | bc
BinaryHexecho "ibase=2; obase=16; $bin" | bc

Converting file permissions (the classic use case):

# Octal permission to symbolic
$ perm=755
$ echo "$(printf "%o" $perm)"
[ 755 ]

# Or read as octal and convert to decimal
$ octal="755"
$ decimal=$(( 0$octal ))
$ echo $decimal
[ 493 ]

# Back to octal with leading zero
$ printf "%#o\n" $decimal
[ 0755 ]

Working with colors (hex โ†’ decimal):

# Hex color #FF8800 โ†’ RGB components
$ hex="FF8800"
$ r=$(( 16#${hex:0:2} ))
$ g=$(( 16#${hex:2:2} ))
$ b=$(( 16#${hex:4:2} ))
$ echo "R=$r G=$g B=$b"
[ R=255 G=136 B=0 ]

# Decimal back to hex color
$ printf "#%02X%02X%02X\n" 255 136 0
[ #FF8800 ]

Bitmask operations:

# Set, clear, and test bits
$ flags=0
$ (( flags |= 0x04 ))     # set bit 2
$ (( flags |= 0x01 ))     # set bit 0
$ echo $flags
[ 5 ]
$ printf "0x%X\n" $flags
[ 0x5 ]

# Test bit 2
$ (( flags & 0x04 )) && echo "bit 2 set"
[ bit 2 set ]

Formatting output with padding:

# Hex with 4 digits, zero-padded
$ printf "%04X\n" 26
[ 001A ]

# Binary with 8 digits
$ printf "%08d\n" $(echo "obase=2; 26" | bc)
[ 00011010 ]

A complete example โ€” all bases for 26:

#!/bin/bash

decimal=26

echo "Decimal: $decimal"
echo "Octal:   $(printf '%o' $decimal)"
echo "Hex:     $(printf '%x' $decimal)"
echo "Binary:  $(echo "obase=2; $decimal" | bc)"
echo

echo "Hex with prefix:  $(printf '%#x' $decimal)"
echo "Octal with prefix: $(printf '%#o' $decimal)"

# Convert back
octal=$(printf '%o' $decimal)
hex=$(printf '%x' $decimal)
binary=$(echo "obase=2; $decimal" | bc)

echo
echo "Verify โ€” back to decimal:"
echo "From octal $octal:   $(( 0$octal ))"
echo "From hex 0x$hex:     $(( 0x$hex ))"
echo "From binary $binary: $(( 2#$binary ))"
[ Decimal: 26 ]
[ Octal:   32 ]
[ Hex:     1a ]
[ Binary:  11010 ]
[ ]
[ Hex with prefix:  0x1a ]
[ Octal with prefix: 032 ]
[ ]
[ Verify โ€” back to decimal: ]
[ From octal 32:   26 ]
[ From hex 0x1a:     26 ]
[ From binary 11010: 26 ]

The full script from the top of the chapter:

#!/bin/bash

octal_value="32"
decimal=$(( 0$octal_value ))
echo $decimal

hex_value="1A"
decimal=$(( 0x$hex_value ))
echo $decimal

binary_value="11010"
decimal=$(( 2#$binary_value ))
echo $decimal

decimal=26
octal=$(printf "%o\n" $decimal)
echo $octal

hex=$(printf "%x\n" $decimal)
echo $hex

binary=$(echo "obase=2; $decimal" | bc)
echo $binary
[ 26 ]
[ 26 ]
[ 26 ]
[ 32 ]
[ 1a ]
[ 11010 ]

Complete Example Session

# ============================================
# PART 1: OCTAL TO DECIMAL
# ============================================

$ octal_value="32"
$ decimal=$(( 0$octal_value ))
$ echo $decimal
[ 26 ]

$ echo $(( 032 ))
[ 26 ]

$ echo $(( 8#32 ))
[ 26 ]

# ============================================
# PART 2: HEX TO DECIMAL
# ============================================

$ hex_value="1A"
$ decimal=$(( 0x$hex_value ))
$ echo $decimal
[ 26 ]

$ echo $(( 0x1A ))
[ 26 ]
$ echo $(( 0x1a ))
[ 26 ]              # case-insensitive

$ echo $(( 16#1A ))
[ 26 ]

# ============================================
# PART 3: BINARY TO DECIMAL
# ============================================

$ binary_value="11010"
$ decimal=$(( 2#$binary_value ))
$ echo $decimal
[ 26 ]

$ echo $(( 2#11010 ))
[ 26 ]

# ============================================
# PART 4: DECIMAL TO OCTAL
# ============================================

$ decimal=26
$ octal=$(printf "%o\n" $decimal)
$ echo $octal
[ 32 ]

$ printf "%#o\n" 26
[ 032 ]

# ============================================
# PART 5: DECIMAL TO HEX
# ============================================

$ hex=$(printf "%x\n" $decimal)
$ echo $hex
[ 1a ]

$ printf "%X\n" 26
[ 1A ]

$ printf "%#x\n" 26
[ 0x1a ]

# ============================================
# PART 6: DECIMAL TO BINARY
# ============================================

$ binary=$(echo "obase=2; $decimal" | bc)
$ echo $binary
[ 11010 ]

$ echo "obase=2; 100" | bc
[ 1100100 ]

# ============================================
# PART 7: BINARY TO HEX VIA BC
# ============================================

$ echo "ibase=2; obase=16; 11010" | bc
[ 1A ]

# ============================================
# PART 8: HEX TO BINARY VIA BC
# ============================================

$ echo "ibase=16; obase=2; 1A" | bc
[ 11010 ]

# ============================================
# PART 9: LEADING ZERO PROBLEM
# ============================================

$ num=025
$ echo $(( num ))
[ 25 ]              # โŒ treated as decimal

$ echo $(( 0$num ))
[ 21 ]              # โœ… forced octal

$ echo $(( 10#025 ))
[ 25 ]              # โœ… forced decimal

# ============================================
# PART 10: INVALID DIGITS
# ============================================

$ var="1G"
$ echo $(( 0x$var ))
[ bash: 0x1G: value too great for base ]

$ echo $(( 08 ))
[ bash: 08: value too great for base ]

$ echo $(( 10#08 ))
[ 8 ]

# ============================================
# PART 11: BASE#NUMBER SYNTAX
# ============================================

$ echo $(( 2#11010 ))
[ 26 ]
$ echo $(( 8#32 ))
[ 26 ]
$ echo $(( 16#1A ))
[ 26 ]
$ echo $(( 10#25 ))
[ 25 ]
$ echo $(( 36#Z ))
[ 35 ]

# ============================================
# PART 12: FILE PERMISSIONS
# ============================================

$ perm="755"
$ decimal=$(( 0$perm ))
$ echo $decimal
[ 493 ]

$ printf "%o\n" 493
[ 755 ]

$ printf "%#o\n" 493
[ 0755 ]

# ============================================
# PART 13: HEX COLOR TO RGB
# ============================================

$ hex="FF8800"
$ r=$(( 16#${hex:0:2} ))
$ g=$(( 16#${hex:2:2} ))
$ b=$(( 16#${hex:4:2} ))
$ echo "R=$r G=$g B=$b"
[ R=255 G=136 B=0 ]

$ printf "#%02X%02X%02X\n" 255 136 0
[ #FF8800 ]

# ============================================
# PART 14: PADDED OUTPUT
# ============================================

$ printf "%04X\n" 26
[ 001A ]

$ printf "%08d\n" $(echo "obase=2; 26" | bc)
[ 00011010 ]

# ============================================
# PART 15: BITMASKS
# ============================================

$ flags=0
$ (( flags |= 0x04 ))
$ (( flags |= 0x01 ))
$ echo $flags
[ 5 ]
$ printf "0x%X\n" $flags
[ 0x5 ]

$ (( flags & 0x04 )) && echo "bit 2 set"
[ bit 2 set ]

# ============================================
# PART 16: FULL SCRIPT
# ============================================

$ cat > bases.sh << 'EOF'
#!/bin/bash

octal_value="32"
decimal=$(( 0$octal_value ))
echo $decimal

hex_value="1A"
decimal=$(( 0x$hex_value ))
echo $decimal

binary_value="11010"
decimal=$(( 2#$binary_value ))
echo $decimal

decimal=26
octal=$(printf "%o\n" $decimal)
echo $octal

hex=$(printf "%x\n" $decimal)
echo $hex

binary=$(echo "obase=2; $decimal" | bc)
echo $binary
EOF
$ chmod +x bases.sh
$ ./bases.sh
[ 26 ]
[ 26 ]
[ 26 ]
[ 32 ]
[ 1a ]
[ 11010 ]

Quick Reference

Number Prefixes

PrefixBaseExampleDecimal
0xHex0x1A26
0Octal03226
0bBinary (bash only)0b1101026
base#Any base2#1101026

Base to Decimal

FromSyntaxExample
Octal$(( 0$var ))$(( 032 )) โ†’ 26
Hex$(( 0x$var ))$(( 0x1A )) โ†’ 26
Binary$(( 2#$var ))$(( 2#11010 )) โ†’ 26
Any$(( base#$var ))$(( 36#Z )) โ†’ 35
Decimal (force)$(( 10#$var ))$(( 10#08 )) โ†’ 8

Decimal to Other Bases

ToCommandExample
Octalprintf "%o\n" $nprintf "%o\n" 26 โ†’ 32
Hexprintf "%x\n" $nprintf "%x\n" 26 โ†’ 1a
HEXprintf "%X\n" $nprintf "%X\n" 26 โ†’ 1A
Binaryecho "obase=2; $n" | bcโ†’ 11010

printf Format Specifiers

FormatMeaningExample
%dDecimal26
%oOctal32
%xHex (lower)1a
%XHex (upper)1A
%#oOctal with 0032
%#xHex with 0x0x1a
%#XHex with 0X0X1A
%04XHex, 4 digits, padded001A

bc Conversions

CommandMeaning
echo "obase=2; N" | bcDecimal โ†’ binary
echo "obase=8; N" | bcDecimal โ†’ octal
echo "obase=16; N" | bcDecimal โ†’ hex
echo "ibase=2; N" | bcBinary โ†’ decimal
echo "ibase=16; N" | bcHex โ†’ decimal
echo "ibase=2; obase=16; N" | bcBinary โ†’ hex

Common Gotchas

ProblemCauseFix
025 = 21, not 25Leading zero = octalUse 10#025
08 errors8 not valid octal digitUse 10#08
0x1G errorsG not valid hexValidate input
0b prefix in old bashNot supportedUse 2#

Best Practices

โœ… Do This:

# Add the prefix inside the arithmetic
decimal=$(( 0$octal_value ))          # โœ…
decimal=$(( 0x$hex_value ))           # โœ…
decimal=$(( 2#$binary_value ))        # โœ…

# Force decimal when leading zeros are possible
echo $(( 10#$num ))                   # โœ…

# Use printf for octal and hex output
printf "%o\n" $n                      # โœ…
printf "%x\n" $n                      # โœ…

# Use bc for binary output
echo "obase=2; $n" | bc               # โœ…

# Validate hex input
[[ "$hex" =~ ^[0-9A-Fa-f]+$ ]] || echo "invalid"  # โœ…

# Use %#o and %#x for prefixed output
printf "%#o\n" $n                     # โœ… 032
printf "%#x\n" $n                     # โœ… 0x1a

โŒ Don’t Do This:

# Don't forget the 0 prefix for octal
decimal=$(( $octal_value ))           # โŒ treats 32 as decimal
decimal=$(( 0$octal_value ))          # โœ…

# Don't trust leading zeros
num=025
echo $(( num ))                       # โŒ 25, not 21
echo $(( 10#$num ))                   # โœ… 25 decimal
echo $(( 0$num ))                     # โœ… 21 octal

# Don't use 0b in old bash
echo $(( 0b1010 ))                    # โš ๏ธ  bash 4.0+ only
echo $(( 2#1010 ))                    # โœ… works everywhere

# Don't assume bash can output binary
echo $(( binary ))                    # โŒ no such thing
echo "obase=2; $n" | bc               # โœ…

# Don't skip validation on user input
hex="$1"
echo $(( 0x$hex ))                    # โŒ errors on bad input
[[ "$hex" =~ ^[0-9A-Fa-f]+$ ]] && echo $(( 0x$hex ))  # โœ…

# Don't forget bc's ibase ordering
echo "obase=2; ibase=16; 1A" | bc     # โš ๏ธ  obase interpreted in base 16
echo "ibase=16; obase=2; 1A" | bc     # โœ…

Common Pitfalls

PitfallProblemSolution
Leading zerosTreated as octalUse 10#
08 or 09Invalid octal digitsUse 10#08
0x with bad hexBash errorValidate input
No binary output in bash$(( )) always decimalUse bc
0b in old bashNot supportedUse 2#
bc ibase before obaseWrong baseSet ibase first
Case-sensitivityHex accepts bothEither case works
Extra output from bcbc prints result + newlineUse $(...) to capture

Real-World Examples

1. Octal to Decimal

#!/bin/bash
octal_value="32"
decimal=$(( 0$octal_value ))
echo $decimal
[ 26 ]

2. Hex to Decimal

#!/bin/bash
hex_value="1A"
decimal=$(( 0x$hex_value ))
echo $decimal
[ 26 ]

3. Binary to Decimal

#!/bin/bash
binary_value="11010"
decimal=$(( 2#$binary_value ))
echo $decimal
[ 26 ]

4. Decimal to Octal

#!/bin/bash
decimal=26
octal=$(printf "%o\n" $decimal)
echo $octal
[ 32 ]

5. Decimal to Hex

#!/bin/bash
decimal=26
hex=$(printf "%x\n" $decimal)
echo $hex
[ 1a ]

6. Decimal to Binary

#!/bin/bash
decimal=26
binary=$(echo "obase=2; $decimal" | bc)
echo $binary
[ 11010 ]

7. All Bases for One Number

#!/bin/bash
n=255
echo "Dec: $n"
echo "Oct: $(printf '%o' $n)"
echo "Hex: $(printf '%x' $n)"
echo "Bin: $(echo "obase=2; $n" | bc)"
[ Dec: 255 ]
[ Oct: 377 ]
[ Hex: ff ]
[ Bin: 11111111 ]

8. File Permissions

#!/bin/bash
perm="755"
decimal=$(( 0$perm ))
echo "755 octal = $decimal decimal"
echo "Back to octal: $(printf '%o' $decimal)"
[ 755 octal = 493 decimal ]
[ Back to octal: 755 ]

9. Hex Color to RGB

#!/bin/bash
hex="FF8800"
r=$(( 16#${hex:0:2} ))
g=$(( 16#${hex:2:2} ))
b=$(( 16#${hex:4:2} ))
echo "R=$r G=$g B=$b"
[ R=255 G=136 B=0 ]

10. RGB to Hex Color

#!/bin/bash
printf "#%02X%02X%02X\n" 255 136 0
[ #FF8800 ]

11. Force Decimal with Leading Zero

#!/bin/bash
num="025"
echo $(( 10#$num ))
[ 25 ]

12. Safe Hex Conversion

#!/bin/bash
hex="$1"
if [[ "$hex" =~ ^[0-9A-Fa-f]+$ ]]; then
    echo $(( 16#$hex ))
else
    echo "Invalid hex: $hex" >&2
    exit 1
fi

13. Safe Octal Conversion

#!/bin/bash
oct="$1"
if [[ "$oct" =~ ^[0-7]+$ ]]; then
    echo $(( 0$oct ))
else
    echo "Invalid octal: $oct" >&2
    exit 1
fi

14. Padded Hex Output

#!/bin/bash
for n in 1 15 255 4095; do
    printf "0x%04X\n" $n
done
[ 0x0001 ]
[ 0x000F ]
[ 0x00FF ]
[ 0x0FFF ]

15. Padded Binary Output

#!/bin/bash
for n in 1 5 10 255; do
    bin=$(echo "obase=2; $n" | bc)
    printf "%08d\n" "$bin"
done
[ 00000001 ]
[ 00000101 ]
[ 00001010 ]
[ 11111111 ]

16. Bitmask Flags

#!/bin/bash
READ=0x01
WRITE=0x02
EXEC=0x04

flags=0
(( flags |= READ ))
(( flags |= EXEC ))

echo "Flags: $(printf '0x%02X' $flags)"

(( flags & READ )) && echo "read enabled"
(( flags & WRITE )) && echo "write enabled"
(( flags & EXEC )) && echo "exec enabled"
[ Flags: 0x05 ]
[ read enabled ]
[ exec enabled ]

17. Decimal to Any Base via bc

#!/bin/bash
n=255
for base in 2 8 16; do
    echo "Base $base: $(echo "obase=$base; $n" | bc)"
done
[ Base 2: 11111111 ]
[ Base 8: 377 ]
[ Base 16: FF ]

18. Any Base to Decimal

#!/bin/bash
echo $(( 2#11010 ))
echo $(( 8#32 ))
echo $(( 16#1A ))
echo $(( 36#Z ))
[ 26 ]
[ 26 ]
[ 26 ]
[ 35 ]

19. IP Address to Integer

#!/bin/bash
ip="192.168.1.1"
IFS=. read -r a b c d <<< "$ip"
n=$(( (a << 24) | (b << 16) | (c << 8) | d ))
echo "$n"
[ 3232235777 ]

printf "%d.%d.%d.%d\n" \
    $(( (n >> 24) & 255 )) \
    $(( (n >> 16) & 255 )) \
    $(( (n >> 8) & 255 )) \
    $(( n & 255 ))
[ 192.168.1.1 ]

20. Full Script

#!/bin/bash

octal_value="32"
decimal=$(( 0$octal_value ))
echo $decimal

hex_value="1A"
decimal=$(( 0x$hex_value ))
echo $decimal

binary_value="11010"
decimal=$(( 2#$binary_value ))
echo $decimal

decimal=26
octal=$(printf "%o\n" $decimal)
echo $octal

hex=$(printf "%x\n" $decimal)
echo $hex

binary=$(echo "obase=2; $decimal" | bc)
echo $binary

Visual: Conversion Map

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Base conversion map                โ”‚
โ”‚                                              โ”‚
โ”‚              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                    โ”‚
โ”‚              โ”‚ DECIMAL  โ”‚                    โ”‚
โ”‚              โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜                    โ”‚
โ”‚                   โ”‚                          โ”‚
โ”‚      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”             โ”‚
โ”‚      โ”‚            โ”‚            โ”‚             โ”‚
โ”‚      โ–ผ            โ–ผ            โ–ผ             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚
โ”‚  โ”‚ OCTAL โ”‚   โ”‚  HEX  โ”‚   โ”‚BINARY โ”‚          โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜          โ”‚
โ”‚      โ”‚           โ”‚           โ”‚              โ”‚
โ”‚      โ”‚  printf   โ”‚  printf   โ”‚  bc          โ”‚
โ”‚      โ”‚  "%o"     โ”‚  "%x"     โ”‚  obase=2     โ”‚
โ”‚      โ”‚           โ”‚           โ”‚              โ”‚
โ”‚      โ”‚           โ”‚           โ”‚              โ”‚
โ”‚  $(( 0$var )) $(( 0x$var )) $(( 2#$var ))   โ”‚
โ”‚      โ”‚           โ”‚           โ”‚              โ”‚
โ”‚      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜              โ”‚
โ”‚                  โ”‚                          โ”‚
โ”‚                  โ–ผ                          โ”‚
โ”‚              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                    โ”‚
โ”‚              โ”‚ DECIMAL  โ”‚                    โ”‚
โ”‚              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                    โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Base Prefixes

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Prefix examples                    โ”‚
โ”‚                                              โ”‚
โ”‚  0x1A      โ†’ hex    โ†’ 26                     โ”‚
โ”‚  032       โ†’ octal  โ†’ 26                     โ”‚
โ”‚  0b11010   โ†’ binary โ†’ 26                     โ”‚
โ”‚  2#11010   โ†’ binary โ†’ 26                     โ”‚
โ”‚  8#32      โ†’ octal  โ†’ 26                     โ”‚
โ”‚  16#1A     โ†’ hex    โ†’ 26                     โ”‚
โ”‚  10#25     โ†’ decimal โ†’ 25                    โ”‚
โ”‚  36#Z      โ†’ base36 โ†’ 35                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

TaskCommandExample
Octal โ†’ Decimal$(( 0$var ))$(( 032 )) โ†’ 26
Hex โ†’ Decimal$(( 0x$var ))$(( 0x1A )) โ†’ 26
Binary โ†’ Decimal$(( 2#$var ))$(( 2#11010 )) โ†’ 26
Any base โ†’ Decimal$(( base#$var ))$(( 36#Z )) โ†’ 35
Force decimal$(( 10#$var ))$(( 10#08 )) โ†’ 8
Decimal โ†’ Octalprintf "%o\n" $nprintf "%o\n" 26 โ†’ 32
Decimal โ†’ Hexprintf "%x\n" $nprintf "%x\n" 26 โ†’ 1a
Decimal โ†’ HEXprintf "%X\n" $nprintf "%X\n" 26 โ†’ 1A
Decimal โ†’ Binaryecho "obase=2; $n" | bcโ†’ 11010
Hex with prefixprintf "%#x\n" $nโ†’ 0x1a
Octal with prefixprintf "%#o\n" $nโ†’ 032
Padded hexprintf "%04X\n" $nโ†’ 001A
Binary โ†’ Hexecho "ibase=2; obase=16; N" | bcโ†’ 1A
Hex โ†’ Binaryecho "ibase=16; obase=2; N" | bcโ†’ 11010

Key takeaways:

  • Bash reads numbers in any base via prefixes: 0x (hex), 0 (octal), 2# (binary), base# (general)
  • Bash only writes decimal from $(( )) โ€” use printf for octal and hex, bc for binary
  • Leading zeros are dangerous โ€” 025 is octal 21, not decimal 25. Use 10# to force decimal
  • 08 and 09 fail as octal โ€” always use 10# when input might have leading zeros
  • Hex is case-insensitive โ€” 1a == 1A
  • Use %#o and %#x to include the base prefix in printf output
  • bc handles any base via ibase (input) and obase (output) โ€” set ibase first
  • Validate input before converting โ€” 0x1G and 08 both crash bash arithmetic
  • Common uses: file permissions (octal), colors (hex), bitmasks (hex/binary), IP addresses (integer)
  • Pad output with printf format widths โ€” %04X, %08d

Remember: Bash arithmetic is flexible about input but fixed on output. Use $(( 0x... )), $(( 0... )), and $(( 2#... )) to read values in any base. Use printf for octal and hex output, and bc for binary. Always guard against leading zeros with 10#. And validate user input before feeding it to $(( )) โ€” one bad digit crashes the script.


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!