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
18Eights
264Sixty-fours
3512File 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
8Basic calculations
64File permissions range
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.