Skip to main content

Octal Number System: Base-8 and File Permissions

What is the Octal Number System?​

Octal is a base-8 number system that uses exactly 8 digits: 0, 1, 2, 3, 4, 5, 6, 7. While we naturally think in decimal (base-10) and computers work in binary (base-2), octal provides a convenient middle ground for certain applications.

Think of octal like having 8 different symbols instead of our usual 10. Just like decimal, each position represents a power of the base - but instead of powers of 10, octal uses powers of 8.

Decimal: Uses 10 digits (0-9), positions are powers of 10
Binary: Uses 2 digits (0-1), positions are powers of 2
Octal: Uses 8 digits (0-7), positions are powers of 8

Why Do We Need Octal?​

You might wonder: "If computers use binary and humans use decimal, why learn octal?" Here are the key reasons:

1. Perfect Binary Grouping​

  • 1 octal digit = exactly 3 binary digits (bits)
  • This makes binary-to-octal conversion extremely simple
  • Much more compact than writing long binary strings

2. Unix/Linux File Permissions​

  • File permissions use 3-bit groups (read, write, execute)
  • Each octal digit perfectly represents one permission group
  • Standard tool: chmod 755 filename

3. Legacy Computer Systems​

  • Older computers used octal for memory addresses
  • Still appears in some programming contexts
  • Understanding it helps with historical code

4. Programming Language Features​

  • JavaScript octal literals: 012 (but with important caveats!)
  • C/C++ octal constants: \012 in strings
  • Python octal: 0o755

Understanding Octal Positions​

Just like other number systems, octal uses positional notation with powers of 8:

Powers of 8 Reference​

PositionPowerValueExample Use
08⁰1Units
18¹8Eights
28²64Sixty-fours
38³512File permissions
48⁴4,096Large numbers

Mathematical Representation​

For any octal number, each digit's value is:

digit × 8^position

Where position starts at 0 from the rightmost digit.

Converting Octal to Decimal: Step-by-Step​

Example 1: Simple Conversion (347₈)​

Octal number: 3 4 7

Step 1: Identify positions and powers
Position: 2 1 0
Digit: 3 4 7
Power of 8: 8² 8¹ 8⁰
Value: 64 8 1

Step 2: Multiply each digit by its position value
3 × 64 = 192
4 × 8 = 32
7 × 1 = 7

Step 3: Add all results
192 + 32 + 7 = 231

Therefore: 347₈ = 231₁₀

Example 2: Larger Number (5632₈)​

Octal number: 5 6 3 2

Positions: 3 2 1 0
Powers: 8³ 8² 8¹ 8⁰
Values: 512 64 8 1

Calculation:
5 × 512 = 2,560
6 × 64 = 384
3 × 8 = 24
2 × 1 = 2

Total: 2,560 + 384 + 24 + 2 = 2,970

Therefore: 5632₈ = 2,970₁₀

Example 3: With Decimal Point (27.5₈)​

Octal number: 2 7 . 5

Positions: 1 0 -1
Powers: 8¹ 8⁰ 8⁻¹
Values: 8 1 0.125

Calculation:
2 × 8 = 16
7 × 1 = 7
5 × 0.125 = 0.625

Total: 16 + 7 + 0.625 = 23.625

Therefore: 27.5₈ = 23.625₁₀

Converting Decimal to Octal: Repeated Division​

Method: Divide by 8, Record Remainders​

The process: divide by 8, write down the remainder, repeat until quotient is 0.

Example 1: Convert 231₁₀ to Octal​

Step 1: 231 ÷ 8 = 28 remainder 7 ← Rightmost digit
Step 2: 28 ÷ 8 = 3 remainder 4
Step 3: 3 ÷ 8 = 0 remainder 3 ← Leftmost digit

Reading remainders from bottom to top: 347₈

Verification: 3×64 + 4×8 + 7×1 = 192 + 32 + 7 = 231 ✓

Therefore: 231₁₀ = 347₈

Example 2: Convert 156₁₀ to Octal​

156 ÷ 8 = 19 remainder 4 ← Rightmost digit
19 ÷ 8 = 2 remainder 3
2 ÷ 8 = 0 remainder 2 ← Leftmost digit

Reading from bottom to top: 234₈

Verification: 2×64 + 3×8 + 4×1 = 128 + 24 + 4 = 156 ✓

Therefore: 156₁₀ = 234₈

Example 3: Convert 1000₁₀ to Octal​

1000 ÷ 8 = 125 remainder 0
125 ÷ 8 = 15 remainder 5
15 ÷ 8 = 1 remainder 7
1 ÷ 8 = 0 remainder 1

Reading from bottom to top: 1750₈

Verification:
1×512 + 7×64 + 5×8 + 0×1 = 512 + 448 + 40 + 0 = 1000 ✓

Therefore: 1000₁₀ = 1750₈

Binary to Octal Conversion: The Easy Way​

Key insight: 1 octal digit = exactly 3 binary digits (bits)

This makes conversion between binary and octal extremely straightforward.

Binary-to-Octal Mapping Table​

BinaryOctalDecimal
00000
00111
01022
01133
10044
10155
11066
11177

Example 1: Convert 101110011₂ to Octal​

Step 1: Group binary digits into sets of 3 (from right to left)
101 110 011

Step 2: Convert each group using the mapping table
101₂ = 5₈
110₂ = 6₈
011₂ = 3₈

Step 3: Write the octal digits in order
563₈

Therefore: 101110011₂ = 563₈

Example 2: Convert 11111010₂ to Octal​

Step 1: Group into sets of 3 from right (add leading zeros if needed)
11 111 010 → 011 111 010

Step 2: Convert each group
011₂ = 3₈
111₂ = 7₈
010₂ = 2₈

Step 3: Combine
372₈

Therefore: 11111010₂ = 372₈

Verification: 372₈ = 3×64 + 7×8 + 2×1 = 192 + 56 + 2 = 250₁₀
Binary: 11111010₂ = 128+64+32+16+8+2 = 250₁₀ ✓

Octal to Binary Conversion​

Reverse process: Each octal digit converts to exactly 3 binary digits.

Example 1: Convert 726₈ to Binary​

Step 1: Convert each octal digit to 3-bit binary
7₈ = 111₂
2₈ = 010₂
6₈ = 110₂

Step 2: Concatenate (join together)
111 010 110

Step 3: Remove spaces (optional)
111010110₂

Therefore: 726₈ = 111010110₂

Example 2: Convert 4537₈ to Binary​

4₈ = 100₂
5₈ = 101₂
3₈ = 011₂
7₈ = 111₂

Concatenate: 100 101 011 111 = 100101011111₂

Therefore: 4537₈ = 100101011111₂

JavaScript and Octal: Important Gotchas​

The Confusing JavaScript Examples Explained​

Let's solve the mystery from the reference examples:

console.log(012 + 2); // Result: 12 (not 14!)
console.log(0128 + 2); // Result: 130 (not 12!)

Why does this happen?

Example 1: 012 + 2 = 12​

// JavaScript interprets 012 as octal (base-8)
let octalNumber = 012; // This is 012₈ (octal)

// Convert 012₈ to decimal:
// 0×8¹ + 1×8¹ + 2×8⁰ = 0×8 + 1×8 + 2×1 = 0 + 8 + 2 = 10₁₀

console.log(012); // Outputs: 10 (decimal)
console.log(012 + 2); // Outputs: 10 + 2 = 12

Example 2: 0128 + 2 = 130​

// JavaScript sees 0128, but 8 is NOT a valid octal digit!
// So it treats 0128 as decimal 128

let notOctal = 0128; // This is just 128₁₀ (decimal)

console.log(0128); // Outputs: 128 (decimal)
console.log(0128 + 2); // Outputs: 128 + 2 = 130

Modern JavaScript Octal Syntax​

Avoid the old 0 prefix! Use the new, clear syntax:

// ❌ Old, confusing syntax (avoid in modern code)
let oldOctal = 012; // Unclear, easy to misread

// ✅ Modern, clear syntax (ES6+)
let newOctal = 0o12; // Clearly indicates octal
let decimal = 0o12; // This equals 10 in decimal

console.log(0o12); // Outputs: 10
console.log(0o755); // Outputs: 493 (common file permission)

// Converting strings
let octalString = "755";
let decimalValue = parseInt(octalString, 8); // 493
console.log(decimalValue);

// Converting to octal string
let decimal = 493;
let octalString = decimal.toString(8); // "755"
console.log(octalString);

Python Octal Examples​

# Python uses 0o prefix for octal literals
octal_num = 0o755 # 493 in decimal
print(octal_num) # 493

# Converting between octal and decimal
decimal = 493
octal_str = oct(decimal) # '0o755'
print(f"Decimal {decimal} = {octal_str}")

# Converting octal string to decimal
octal_string = "755"
decimal_value = int(octal_string, 8) # 493
print(f"Octal {octal_string} = {decimal_value}")

Unix/Linux File Permissions: The Main Use Case​

This is the most important practical application of octal in modern computing.

Understanding File Permissions​

Every file and directory has three types of permissions for three groups of users:

Permission Types:

  • r (read): Can view file contents or list directory
  • w (write): Can modify file or create/delete files in directory
  • x (execute): Can run file as program or enter directory

User Groups:

  • Owner: The user who created the file
  • Group: Users in the same group as the file
  • Others: Everyone else on the system

Binary Representation of Permissions​

Each permission is represented by 1 bit:

Permission bits: rwx
Binary values: 421

r (read) = 4 = 100₂
w (write) = 2 = 010₂
x (execute) = 1 = 001₂

Converting Permissions to Octal​

Each group of 3 permission bits = 1 octal digit

Full permissions: rwxrwxrwx (9 bits total)
Grouped: rwx rwx rwx (3 groups of 3 bits)
--- --- ---
7 7 7 (in octal)

Common Permission Examples​

OctalBinaryPermissionsMeaning
0000---No permissions
1001--xExecute only
2010-w-Write only
3011-wxWrite and execute
4100r--Read only
5101r-xRead and execute
6110rw-Read and write
7111rwxRead, write, and execute

Real-World Permission Examples​

Example 1: chmod 755 script.sh​

755₈ breaks down as:
7 = 111₂ = rwx (Owner can read, write, execute)
5 = 101₂ = r-x (Group can read and execute, not write)
5 = 101₂ = r-x (Others can read and execute, not write)

This is perfect for executable scripts that everyone can run
but only the owner can modify.

Example 2: chmod 644 document.txt​

644₈ breaks down as:
6 = 110₂ = rw- (Owner can read and write)
4 = 100₂ = r-- (Group can only read)
4 = 100₂ = r-- (Others can only read)

This is perfect for documents that the owner can edit
but others can only view.

Example 3: chmod 700 private-file.txt​

700₈ breaks down as:
7 = 111₂ = rwx (Owner has full access)
0 = 000₂ = --- (Group has no access)
0 = 000₂ = --- (Others have no access)

This is perfect for private files that only the owner can access.

Setting Permissions with chmod​

# Give full permissions to owner, read+execute to others
chmod 755 script.sh

# Make file readable/writable by owner, readable by others
chmod 644 document.txt

# Make file private to owner only
chmod 700 secret.txt

# Make directory accessible to group members
chmod 750 shared-folder/

# Remove all permissions from others
chmod 770 group-project/

Viewing Current Permissions​

# List files with permissions
ls -l

# Example output:
# -rwxr-xr-x 1 user group 1234 Jan 1 12:00 script.sh
# ^^^^^^^^^
# ||||||||\-- Others: r-x (5)
# |||||||\--- Group: r-x (5)
# ||||||\---- Owner: rwx (7)
# ||||||----- File type: - (regular file)
#
# So this file has permissions 755

Octal Arithmetic Examples​

Addition: 345₈ + 127₈​

3 4 5
+ 1 2 7
-------

Step-by-step (right to left):
Column 1: 5 + 7 = 12₁₀ = 14₈ (write 4, carry 1)
Column 2: 4 + 2 + 1(carry) = 7₈ (write 7)
Column 3: 3 + 1 = 4₈ (write 4)

Result: 474₈

Verification in decimal:
345₈ = 3×64 + 4×8 + 5 = 229₁₀
127₈ = 1×64 + 2×8 + 7 = 87₁₀
229 + 87 = 316₁₀

474₈ = 4×64 + 7×8 + 4 = 316₁₀ ✓

Subtraction: 752₈ - 236₈​

7 5 2
- 2 3 6
-------

Step-by-step (right to left):
Column 1: 2 - 6 (can't do, need to borrow)
Borrow 1 from next column: (8 + 2) - 6 = 4
Column 2: (5 - 1) - 3 = 1 (after lending 1)
Column 3: 7 - 2 = 5

Result: 514₈

Verification:
752₈ = 7×64 + 5×8 + 2 = 490₁₀
236₈ = 2×64 + 3×8 + 6 = 158₁₀
490 - 158 = 332₁₀

514₈ = 5×64 + 1×8 + 4 = 332₁₀ ✓

Programming Examples and Practical Usage​

JavaScript: Working with Octal​

// Modern octal literals (ES6+)
const filePermission = 0o755; // 493 in decimal
console.log(
`Permission ${filePermission.toString(8)} in decimal: ${filePermission}`
);

// Converting between number systems
function convertOctal(octalString) {
const decimal = parseInt(octalString, 8);
const binary = decimal.toString(2);
const hex = decimal.toString(16);

return {
octal: octalString,
decimal: decimal,
binary: binary,
hexadecimal: hex,
};
}

console.log(convertOctal("755"));
// Output: { octal: "755", decimal: 493, binary: "111101101", hexadecimal: "1ed" }

// File permission checker
function checkPermissions(octal) {
const permissions = ["---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"];

const digits = octal.toString().split("").map(Number);

return {
owner: permissions[digits[0]] || "???",
group: permissions[digits[1]] || "???",
others: permissions[digits[2]] || "???",
};
}

console.log(checkPermissions(755));
// Output: { owner: 'rwx', group: 'r-x', others: 'r-x' }

Python: File System Operations​

import os
import stat

# Setting file permissions using octal
filename = "example.txt"

# Create file with specific permissions
with open(filename, 'w') as f:
f.write("Hello, World!")

# Set permissions: owner can read/write, others can only read
os.chmod(filename, 0o644)

# Read current permissions
file_stats = os.stat(filename)
permissions = oct(file_stats.st_mode)[-3:] # Get last 3 digits
print(f"File permissions: {permissions}")

# Check specific permissions
def has_permission(file_path, permission_type):
"""Check if file has specific permission for owner"""
file_mode = os.stat(file_path).st_mode

if permission_type == 'read':
return bool(file_mode & stat.S_IRUSR)
elif permission_type == 'write':
return bool(file_mode & stat.S_IWUSR)
elif permission_type == 'execute':
return bool(file_mode & stat.S_IXUSR)

return False

print(f"Can read: {has_permission(filename, 'read')}")
print(f"Can write: {has_permission(filename, 'write')}")
print(f"Can execute: {has_permission(filename, 'execute')}")

# Common permission patterns
PERMISSIONS = {
'private_file': 0o600, # rw-------
'public_readable': 0o644, # rw-r--r--
'executable': 0o755, # rwxr-xr-x
'script': 0o755, # rwxr-xr-x
'directory': 0o755, # rwxr-xr-x
'private_dir': 0o700, # rwx------
}

# Apply permissions
for name, perm in PERMISSIONS.items():
print(f"{name}: {oct(perm)} ({perm:o})")

Quick Reference Tables​

Decimal to Octal Conversion (0-20)​

DecimalOctalBinary
00000
11001
77111
8101000
15171111
162010000
202410100
641001000000

File Permission Quick Reference​

OctalBinaryrwxUse Case
755111101101rwxr-xr-xExecutable files
644110100100rw-r--r--Regular files
600110000000rw-------Private files
777111111111rwxrwxrwxFull access (dangerous!)
700111000000rwx------Private executable
666110110110rw-rw-rw-Group writable

Powers of 8 Reference​

PowerValueCommon Use
8⁰1Units place
8¹8Basic calculations
8²64File permissions range
8³512Large file permissions
8⁴4,096Memory calculations

Common Mistakes and Troubleshooting​

Mistake 1: Invalid Octal Digits​

// ❌ Wrong: Using digits 8 or 9 in octal
let invalid = 0o789; // SyntaxError! 8 and 9 don't exist in octal

// ✅ Correct: Only use digits 0-7
let valid = 0o567; // This works fine

Mistake 2: Confusing Octal and Decimal​

# ❌ Wrong: Thinking 755 is a decimal number
# When you see 755 in context of chmod, it's octal!

# ✅ Correct: Understanding 755 as octal
chmod 755 file.txt # This is 755₈ = 493₁₀

Mistake 3: Forgetting Leading Zeros in Binary Grouping​

❌ Wrong: 11111010₂ → 11 111 010 → ? 7 2 (invalid first group)
✅ Correct: 11111010₂ → 011 111 010 → 3 7 2₈

Mistake 4: JavaScript Octal Confusion​

// ❌ Confusing: Old syntax can be misread
let unclear = 012; // Is this octal or just a number?

// ✅ Clear: Use modern syntax
let clear = 0o12; // Obviously octal
let decimal = 12; // Obviously decimal

Why Octal is Less Common Now​

Historical Context​

  • 1960s-1970s: Octal was popular because early computers used 12, 18, or 36-bit words
  • 1980s+: Computers standardized on 8-bit bytes and 32/64-bit words
  • Modern era: Hexadecimal (base-16) became preferred because 4 bits = 1 hex digit

Current Usage​

Still important for:

  • Unix/Linux file permissions (main use case)
  • Legacy code and systems
  • Understanding computer science fundamentals
  • Some escape sequences in programming

Replaced by hexadecimal for:

  • Memory addresses
  • Color codes
  • Binary data representation
  • Debugging output

Key Takeaways​

✅ Octal uses 8 digits (0-7) with positions as powers of 8
✅ 1 octal digit = 3 binary bits (perfect grouping)
✅ Main modern use: Unix/Linux file permissions (chmod 755)
✅ Easy binary conversion through 3-bit grouping
✅ JavaScript gotcha: 012 is octal, use 0o12 in modern code
✅ File permissions: Each octal digit represents rwx for owner/group/others
✅ Less common than hex in modern computing but still essential for system administration

Understanding octal is crucial for:

  • Managing file and directory permissions on Unix/Linux systems
  • Reading and understanding legacy code
  • Converting between different number systems
  • Understanding computer science number theory
  • Debugging low-level system issues

While not as ubiquitous as binary or hexadecimal, octal remains an important tool in a developer's toolkit, especially for system administration and understanding how computers represent data in groups of three bits.