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
Position | Power | Value | Example Use |
---|---|---|---|
0 | 8⁰ | 1 | Units |
1 | 8¹ | 8 | Eights |
2 | 8² | 64 | Sixty-fours |
3 | 8³ | 512 | File permissions |
4 | 8⁴ | 4,096 | Large 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
Binary | Octal | Decimal |
---|---|---|
000 | 0 | 0 |
001 | 1 | 1 |
010 | 2 | 2 |
011 | 3 | 3 |
100 | 4 | 4 |
101 | 5 | 5 |
110 | 6 | 6 |
111 | 7 | 7 |
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
Octal | Binary | Permissions | Meaning |
---|---|---|---|
0 | 000 | --- | No permissions |
1 | 001 | --x | Execute only |
2 | 010 | -w- | Write only |
3 | 011 | -wx | Write and execute |
4 | 100 | r-- | Read only |
5 | 101 | r-x | Read and execute |
6 | 110 | rw- | Read and write |
7 | 111 | rwx | Read, 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)
Decimal | Octal | Binary |
---|---|---|
0 | 0 | 000 |
1 | 1 | 001 |
7 | 7 | 111 |
8 | 10 | 1000 |
15 | 17 | 1111 |
16 | 20 | 10000 |
20 | 24 | 10100 |
64 | 100 | 1000000 |
File Permission Quick Reference
Octal | Binary | rwx | Use Case |
---|---|---|---|
755 | 111101101 | rwxr-xr-x | Executable files |
644 | 110100100 | rw-r--r-- | Regular files |
600 | 110000000 | rw------- | Private files |
777 | 111111111 | rwxrwxrwx | Full access (dangerous!) |
700 | 111000000 | rwx------ | Private executable |
666 | 110110110 | rw-rw-rw- | Group writable |
Powers of 8 Reference
Power | Value | Common Use |
---|---|---|
8⁰ | 1 | Units place |
8¹ | 8 | Basic calculations |
8² | 64 | File permissions range |
8³ | 512 | Large file permissions |
8⁴ | 4,096 | Memory 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.