Shell Mathematics: Linux as Your Calculator
Linux IS your calculator. This reference covers using bash, awk, bc, and other CLI tools for mathematical operations - from basic arithmetic to cryptographic foundations.
Source file: examples/codex/bash/math/
Topics Covered
1. Brace Expansion (Combinatorics)
Brace expansion as Cartesian product, arithmetic sequences, nested expansion.
The Cartesian Product
Brace expansion is the Cartesian product in shell syntax.
In set theory: A × B = {(a,b) | a ∈ A, b ∈ B}
In bash:
# Set A = {a, b}, Set B = {1, 2}
# A × B = {a1, a2, b1, b2}
echo {a,b}{1,2}
# Output: a1 a2 b1 b2
# Three sets: |A| × |B| × |C| = 2 × 2 × 2 = 8 elements
echo {a,b}{1,2}{x,y}
# Output: a1x a1y a2x a2y b1x b1y b2x b2y
# Practical: Create test matrix (3 × 2 = 6 files)
touch test-{small,medium,large}-{pass,fail}.log
2. Arithmetic Expansion
Integer arithmetic, comparison operators, ternary expressions.
Integer Arithmetic
Bash performs integer arithmetic natively with $.
# Basic operations
echo $((5 + 3)) # 8 (addition)
echo $((10 - 4)) # 6 (subtraction)
echo $((6 * 7)) # 42 (multiplication)
echo $((20 / 3)) # 6 (integer division - truncates)
echo $((20 % 3)) # 2 (modulo - remainder)
echo $((2 ** 10)) # 1024 (exponentiation)
# Variables (no $ needed inside $(( )))
x=5; y=3
echo $((x + y)) # 8
echo $((x * y)) # 15
echo $((x ** y)) # 125 (5³)
# Compound assignment
((x += 5)) # x = x + 5
((x++)) # x = x + 1 (post-increment)
((++x)) # x = x + 1 (pre-increment)
3. Numeral Systems (Baldor-style)
From unary to hexadecimal - the mathematical theory behind number bases.
Positional Notation - The Foundation
Every number system uses positional notation where digit position determines value.
In base b, a number d₃d₂d₁d₀ means:
d₃×b³ + d₂×b² + d₁×b¹ + d₀×b⁰
# Decimal 1234 = 1×10³ + 2×10² + 3×10¹ + 4×10⁰
echo $((1*10**3 + 2*10**2 + 3*10**1 + 4*10**0))
# Output: 1234
# Binary 1101 = 1×2³ + 1×2² + 0×2¹ + 1×2⁰
echo $((1*2**3 + 1*2**2 + 0*2**1 + 1*2**0))
# Output: 13
# Hex A3 = 10×16¹ + 3×16⁰
echo $((10*16**1 + 3*16**0))
# Output: 163
Unary (Base 1) - The Simplest System
Unary uses only ONE symbol. Count = number of symbols.
| = 1 || = 2 ||| = 3 |||| = 4
# Convert decimal to unary (tally marks)
decimal_to_unary() {
local n=$1
printf '|%.0s' $(seq 1 $n)
echo
}
decimal_to_unary 5
# Output: |||||
# Convert unary to decimal
unary_to_decimal() {
echo "${#1}" # String length
}
unary_to_decimal "|||||||"
# Output: 7
# Unary addition is concatenation!
a="|||"
b="||||"
echo "${a}${b}" # ||||||| = 7
Historical note: Tally marks, Roman numerals (partially), and Peano arithmetic use unary concepts.
Binary (Base 2) - The Computer’s Language
Only digits: 0, 1
Decimal | Binary | Powers of 2 --------|--------|------------- 0 | 0 | 0 1 | 1 | 2⁰ 2 | 10 | 2¹ 3 | 11 | 2¹ + 2⁰ 4 | 100 | 2² 5 | 101 | 2² + 2⁰ 8 |1000 | 2³ 16 |10000 | 2⁴ 255 |11111111| 2⁸ - 1
# Binary to decimal
echo $((2#11111111)) # 255
echo $((2#10101010)) # 170
# Decimal to binary
dec_to_bin() {
local n=$1 result=""
while [[ $n -gt 0 ]]; do
result="$((n % 2))$result"
n=$((n / 2))
done
echo "${result:-0}"
}
dec_to_bin 42
# Output: 101010
# Using bc (easier)
echo "obase=2; 42" | bc
# Output: 101010
# Print binary with leading zeros (8-bit)
printf "%08d\n" $(echo "obase=2; 42" | bc)
# Output: 00101010
Octal (Base 8) - Unix Permissions
Digits: 0-7. Each octal digit = 3 binary digits.
Octal | Binary | Decimal | Permission ------|--------|---------|---------- 0 | 000 | 0 | --- 1 | 001 | 1 | --x 2 | 010 | 2 | -w- 3 | 011 | 3 | -wx 4 | 100 | 4 | r-- 5 | 101 | 5 | r-x 6 | 110 | 6 | rw- 7 | 111 | 7 | rwx
# Octal to decimal
echo $((8#755)) # 493
echo $((8#644)) # 420
# Decimal to octal
printf "%o\n" 493 # 755
echo "obase=8; 493" | bc # 755
# File permissions in action
# rwxr-xr-x = 111 101 101 = 7 5 5 = 755
echo $((2#111101101)) # 493
# Why octal for permissions?
# 3 categories (owner, group, other) × 3 bits each = 9 bits
# 9 bits divides evenly by 3 → perfect for octal
Hexadecimal (Base 16) - The Programmer’s Choice
Digits: 0-9, A-F (10-15). Each hex digit = 4 binary digits (nibble).
Hex | Binary | Decimal ----|--------|-------- 0 | 0000 | 0 1 | 0001 | 1 ... 9 | 1001 | 9 A | 1010 | 10 B | 1011 | 11 C | 1100 | 12 D | 1101 | 13 E | 1110 | 14 F | 1111 | 15
# Hex to decimal
echo $((16#FF)) # 255
echo $((16#CAFE)) # 51966
echo $((16#DEADBEEF)) # 3735928559
# Decimal to hex
printf "%x\n" 255 # ff
printf "%X\n" 255 # FF
printf "%08X\n" 255 # 000000FF (8 digits, zero-padded)
echo "obase=16; 255" | bc # FF
# Hex color codes (RGB)
# #FF5733 = Red=255, Green=87, Blue=51
echo "Red: $((16#FF)), Green: $((16#57)), Blue: $((16#33))"
# MAC addresses: 6 bytes = 12 hex digits
mac="AA:BB:CC:DD:EE:FF"
echo "$mac" | tr -d ':' | fold -w2 | while read byte; do
echo -n "$((16#$byte)) "
done
echo
# Output: 170 187 204 221 238 255
Converting Between Any Bases
The universal algorithm: base₁ → decimal → base₂
# General base conversion with bc
# obase = output base, ibase = input base
# IMPORTANT: set obase BEFORE ibase!
# Binary to octal
echo "obase=8; ibase=2; 11111111" | bc
# Output: 377
# Octal to hex
echo "obase=16; ibase=8; 755" | bc
# Output: 1ED
# Hex to binary
echo "obase=2; ibase=16; FF" | bc
# Output: 11111111
# Base 5 to decimal (exotic)
echo "ibase=5; 1234" | bc
# 1×5³ + 2×5² + 3×5¹ + 4×5⁰ = 125 + 50 + 15 + 4 = 194
# Output: 194
# Bash native: base 2-64 input
echo $((36#ZZ)) # Base 36: Z=35, so ZZ = 35×36 + 35 = 1295
echo $((62#aZ)) # Base 62 (0-9, a-z, A-Z)
Quick Reference Table
| Decimal | Binary | Octal | Hex | Powers |
|---|---|---|---|---|
0 |
0 |
0 |
0 |
- |
1 |
1 |
1 |
1 |
2⁰ |
2 |
10 |
2 |
2 |
2¹ |
4 |
100 |
4 |
4 |
2² |
8 |
1000 |
10 |
8 |
2³ |
16 |
10000 |
20 |
10 |
2⁴ |
32 |
100000 |
40 |
20 |
2⁵ |
64 |
1000000 |
100 |
40 |
2⁶ |
128 |
10000000 |
200 |
80 |
2⁷ |
255 |
11111111 |
377 |
FF |
2⁸-1 |
256 |
100000000 |
400 |
100 |
2⁸ |
# Generate this table programmatically
for n in 0 1 2 4 8 16 32 64 128 255 256; do
printf "%3d | %9s | %3o | %3X\n" \
$n "$(echo "obase=2; $n" | bc)" $n $n
done
4. Bitwise Operations
AND, OR, XOR, shifts - for networking and cryptography.
Bitwise Operators
Critical for networking, cryptography, and systems programming.
# AND (&) - both bits must be 1
echo $((12 & 10))
# 1100 (12)
# & 1010 (10)
# = 1000 (8)
# Output: 8
# OR (|) - either bit is 1
echo $((12 | 10))
# 1100 (12)
# | 1010 (10)
# = 1110 (14)
# Output: 14
# XOR (^) - bits are different
echo $((12 ^ 10))
# 1100 (12)
# ^ 1010 (10)
# = 0110 (6)
# Output: 6
# NOT (~) - flip all bits (two's complement)
echo $((~12))
# Output: -13 (in two's complement)
# Left shift (<<) - multiply by 2^n
echo $((1 << 8)) # 256 (1 × 2⁸)
echo $((5 << 2)) # 20 (5 × 2² = 5 × 4)
# Right shift (>>) - divide by 2^n
echo $((256 >> 4)) # 16 (256 ÷ 2⁴ = 256 ÷ 16)
Subnet Calculations
Apply bitwise AND to calculate network address.
# Network address = IP AND Subnet Mask
# IP: 192.168.1.100, Mask: 255.255.255.0 (/24)
ip_dec=$((192 * 256**3 + 168 * 256**2 + 1 * 256 + 100))
mask_dec=$((255 * 256**3 + 255 * 256**2 + 255 * 256 + 0))
network=$((ip_dec & mask_dec))
printf "IP: %d.%d.%d.%d\n" $((ip_dec >> 24 & 255)) $((ip_dec >> 16 & 255)) $((ip_dec >> 8 & 255)) $((ip_dec & 255))
printf "Mask: %d.%d.%d.%d\n" $((mask_dec >> 24 & 255)) $((mask_dec >> 16 & 255)) $((mask_dec >> 8 & 255)) $((mask_dec & 255))
printf "Network: %d.%d.%d.%d\n" $((network >> 24 & 255)) $((network >> 16 & 255)) $((network >> 8 & 255)) $((network & 255))
# Output:
# IP: 192.168.1.100
# Mask: 255.255.255.0
# Network: 192.168.1.0
# CIDR to subnet mask
cidr=24
mask=$(( (0xFFFFFFFF << (32 - cidr)) & 0xFFFFFFFF ))
printf "%d.%d.%d.%d\n" $((mask >> 24 & 255)) $((mask >> 16 & 255)) $((mask >> 8 & 255)) $((mask & 255))
# Output: 255.255.255.0
Bit Flags (Unix Permissions)
File permissions are bit flags.
# rwxrwxrwx = 9 bits = 3 octal digits
# r=4 (100), w=2 (010), x=1 (001)
# Check if executable (owner)
perms=755 # rwxr-xr-x
echo $(( (8#$perms >> 6) & 1 )) # 1 (owner can execute)
# Set specific permission bits
read_bit=4
write_bit=2
exec_bit=1
owner_perms=$((read_bit | write_bit | exec_bit)) # 7 (rwx)
group_perms=$((read_bit | exec_bit)) # 5 (r-x)
other_perms=$((read_bit | exec_bit)) # 5 (r-x)
echo "${owner_perms}${group_perms}${other_perms}" # 755
# umask calculation
# Default file: 666, Default dir: 777
# umask 022: files get 644, dirs get 755
echo $((8#666 & ~8#022)) # 644
echo $((8#777 & ~8#022)) # 755
bc - Arbitrary Precision Calculator
Bash only does integers. Use bc for floating point.
# Basic floating point
echo "5.5 + 3.2" | bc
# Output: 8.7
# Set precision with scale
echo "scale=10; 22/7" | bc
# Output: 3.1428571428
# Square root
echo "scale=10; sqrt(2)" | bc
# Output: 1.4142135623
# Powers and logarithms (need -l for math library)
echo "scale=10; e(1)" | bc -l # e^1 = 2.718...
echo "scale=10; l(10)" | bc -l # ln(10) = 2.302...
echo "scale=10; s(0)" | bc -l # sin(0) = 0
echo "scale=10; c(0)" | bc -l # cos(0) = 1
echo "scale=10; a(1)" | bc -l # atan(1) = 0.785... (π/4)
# Calculate π
echo "scale=50; 4*a(1)" | bc -l
# 3.14159265358979323846264338327950288419716939937510
awk - Floating Point and More
awk handles floats natively and is more powerful than bc for data processing.
# Basic math
awk 'BEGIN {print 5.5 + 3.2}' # 8.7
awk 'BEGIN {print 22/7}' # 3.14286
awk 'BEGIN {printf "%.10f\n", 22/7}' # 3.1428571429
# Built-in functions
awk 'BEGIN {print sqrt(2)}' # 1.41421
awk 'BEGIN {print sin(3.14159/2)}' # 1 (sin 90°)
awk 'BEGIN {print cos(0)}' # 1
awk 'BEGIN {print exp(1)}' # 2.71828 (e)
awk 'BEGIN {print log(10)}' # 2.30259 (ln)
awk 'BEGIN {print atan2(1,1)}' # 0.785398 (π/4)
# Calculate π
awk 'BEGIN {printf "%.50f\n", 4*atan2(1,1)}'
# Exponents
awk 'BEGIN {print 2^10}' # 1024
awk 'BEGIN {print 10^(-3)}' # 0.001
Modular Arithmetic (Foundation of Cryptography)
# Basic modulo
echo $((17 % 5)) # 2 (17 = 3×5 + 2)
echo $((100 % 7)) # 2
# Clock arithmetic (12-hour)
hour=23
echo $((hour % 12)) # 11 (11 PM)
# Wrap-around (circular buffer index)
size=8
for i in {0..15}; do
echo "i=$i -> index=$((i % size))"
done
# Check divisibility
n=42
[[ $((n % 2)) -eq 0 ]] && echo "even" || echo "odd"
[[ $((n % 3)) -eq 0 ]] && echo "divisible by 3"
Cryptographic Applications
# Modular exponentiation (a^b mod m)
# Used in RSA, Diffie-Hellman
# WARNING: Bash integers overflow! Use bc for real crypto
# Simple example: 3^5 mod 7
a=3; b=5; m=7
result=1
for ((i=0; i<b; i++)); do
result=$(( (result * a) % m ))
done
echo $result # 5 (243 mod 7 = 5)
# With bc for larger numbers
echo "3^1000 % 17" | bc
# Output: 1
# Caesar cipher (shift cipher)
# Encrypt: shift = 3
shift=3
char='A'
ascii=$(printf "%d" "'$char")
shifted=$(( (ascii - 65 + shift) % 26 + 65 ))
printf "\\$(printf '%03o' $shifted)\n" # D
# XOR cipher (symmetric encryption basis)
plaintext=65 # 'A'
key=42
cipher=$((plaintext ^ key))
decrypted=$((cipher ^ key))
echo "Plain: $plaintext, Cipher: $cipher, Decrypted: $decrypted"
# Output: Plain: 65, Cipher: 107, Decrypted: 65
Set Operations
Using sort, uniq, comm, and process substitution.
# Define sets as files or arrays
set_a=(1 2 3 4 5)
set_b=(4 5 6 7 8)
# Union (A ∪ B) - all elements
printf '%s\n' "${set_a[@]}" "${set_b[@]}" | sort -u
# 1 2 3 4 5 6 7 8
# Intersection (A ∩ B) - common elements
comm -12 <(printf '%s\n' "${set_a[@]}" | sort) \
<(printf '%s\n' "${set_b[@]}" | sort)
# 4 5
# Difference (A - B) - in A but not B
comm -23 <(printf '%s\n' "${set_a[@]}" | sort) \
<(printf '%s\n' "${set_b[@]}" | sort)
# 1 2 3
# Symmetric difference (A △ B) - in either but not both
comm -3 <(printf '%s\n' "${set_a[@]}" | sort) \
<(printf '%s\n' "${set_b[@]}" | sort) | tr -d '\t'
# 1 2 3 6 7 8
# Cardinality (|A|)
echo "${#set_a[@]}" # 5
Quick Reference
| Tool | Best For | Example |
|---|---|---|
|
Integer arithmetic, bitwise ops |
|
|
Arbitrary precision, floating point |
|
|
Math functions (sin, cos, log, exp) |
|
|
Floating point in pipelines |
|
|
Complex math, one-liners |
|
|
RPN calculator (stack-based) |
|
|
Base conversion output |
|
Python One-Liners
When you need serious math libraries.
# Basic math
python3 -c "print(22/7)"
python3 -c "print(2**100)" # Big integers no problem
# Math module
python3 -c "import math; print(math.pi)"
python3 -c "import math; print(math.sqrt(2))"
python3 -c "import math; print(math.factorial(10))"
python3 -c "import math; print(math.gcd(48, 18))"
# Complex numbers
python3 -c "print((3+4j) * (1-2j))"
# Statistics
python3 -c "import statistics; print(statistics.mean([1,2,3,4,5]))"
python3 -c "import statistics; print(statistics.stdev([1,2,3,4,5]))"
# Hex/binary
python3 -c "print(bin(255))" # 0b11111111
python3 -c "print(hex(255))" # 0xff
python3 -c "print(int('FF', 16))" # 255
dc - RPN Stack Calculator
Reverse Polish Notation. Operands first, then operator.
# Basic: push 2, push 3, add, print
echo "2 3 + p" | dc
# Output: 5
# 2^10
echo "2 10 ^ p" | dc
# Output: 1024
# Set precision, calculate sqrt(2)
echo "10 k 2 v p" | dc
# Output: 1.4142135623
# Stack operations
echo "1 2 3 f" | dc # f = print stack
# 3
# 2
# 1
# Factorial using recursion
echo "[d1-d1<f*]sf 10 lfx p" | dc
# Output: 3628800
Network Engineering Calculations
# How many /27 subnets fit in a /24?
echo $((2 ** (27 - 24))) # 8 subnets
# Hosts per subnet
for cidr in 24 25 26 27 28 29 30; do
hosts=$((2 ** (32 - cidr) - 2))
printf "/%d = %d hosts\n" $cidr $hosts
done
# Is this IP in this subnet?
ip_to_dec() {
IFS='.' read -r a b c d <<< "$1"
echo $((a * 256**3 + b * 256**2 + c * 256 + d))
}
ip=$(ip_to_dec "192.168.1.100")
network=$(ip_to_dec "192.168.1.0")
mask=$((0xFFFFFF00)) # /24
if [[ $((ip & mask)) -eq $((network & mask)) ]]; then
echo "IP is in subnet"
fi
Cryptography Basics
# Generate random bytes (hex)
head -c 16 /dev/urandom | xxd -p
# Output: a7f3b2c1... (32 hex chars = 128 bits)
# Hash a string
echo -n "password" | sha256sum | awk '{print $1}'
# Check if number is prime (naive)
is_prime() {
local n=$1
[[ $n -lt 2 ]] && return 1
for ((i=2; i*i<=n; i++)); do
[[ $((n % i)) -eq 0 ]] && return 1
done
return 0
}
is_prime 17 && echo "17 is prime"
# GCD using Euclidean algorithm
gcd() {
local a=$1 b=$2
while [[ $b -ne 0 ]]; do
local t=$b
b=$((a % b))
a=$t
done
echo $a
}
gcd 48 18 # Output: 6
Subnet Fundamentals
IPv4 = 32 bits. CIDR notation /X means X bits for network, (32-X) bits for hosts.
# The magic formula: 2^(32-CIDR) = total addresses
# Usable hosts = 2^(32-CIDR) - 2 (network + broadcast)
# Generate hosts table
echo "CIDR | Mask | Total | Usable | Common Use"
echo "-----|------|-------|--------|----------"
for cidr in 8 16 20 21 22 23 24 25 26 27 28 29 30 31 32; do
total=$((2 ** (32 - cidr)))
usable=$((total - 2))
[[ $usable -lt 0 ]] && usable=0
# Calculate mask
mask=$(( (0xFFFFFFFF << (32 - cidr)) & 0xFFFFFFFF ))
mask_str=$(printf "%d.%d.%d.%d" \
$((mask >> 24 & 255)) $((mask >> 16 & 255)) \
$((mask >> 8 & 255)) $((mask & 255)))
printf "/%2d | %-15s | %8d | %7d\n" $cidr "$mask_str" $total $usable
done
Output:
CIDR | Mask | Total | Usable -----|-----------------|----------|-------- /8 | 255.0.0.0 | 16777216 | 16777214 /16 | 255.255.0.0 | 65536 | 65534 /20 | 255.255.240.0 | 4096 | 4094 /21 | 255.255.248.0 | 2048 | 2046 /22 | 255.255.252.0 | 1024 | 1022 /23 | 255.255.254.0 | 512 | 510 /24 | 255.255.255.0 | 256 | 254 /25 | 255.255.255.128 | 128 | 126 /26 | 255.255.255.192 | 64 | 62 /27 | 255.255.255.224 | 32 | 30 /28 | 255.255.255.240 | 16 | 14 /29 | 255.255.255.248 | 8 | 6 /30 | 255.255.255.252 | 4 | 2 (point-to-point) /31 | 255.255.255.254 | 2 | 0 (RFC 3021) /32 | 255.255.255.255 | 1 | 0 (host route)
Subnet Calculator Functions
# IP to decimal
ip_to_dec() {
IFS='.' read -r a b c d <<< "$1"
echo $((a << 24 | b << 16 | c << 8 | d))
}
# Decimal to IP
dec_to_ip() {
printf "%d.%d.%d.%d\n" \
$(($1 >> 24 & 255)) $(($1 >> 16 & 255)) \
$(($1 >> 8 & 255)) $(($1 & 255))
}
# CIDR to subnet mask
cidr_to_mask() {
local cidr=$1
local mask=$(( (0xFFFFFFFF << (32 - cidr)) & 0xFFFFFFFF ))
dec_to_ip $mask
}
# Get network address (IP AND mask)
network_addr() {
local ip=$1 cidr=$2
local ip_dec=$(ip_to_dec "$ip")
local mask=$(( (0xFFFFFFFF << (32 - cidr)) & 0xFFFFFFFF ))
dec_to_ip $((ip_dec & mask))
}
# Get broadcast address (IP OR ~mask)
broadcast_addr() {
local ip=$1 cidr=$2
local ip_dec=$(ip_to_dec "$ip")
local mask=$(( (0xFFFFFFFF << (32 - cidr)) & 0xFFFFFFFF ))
local wildcard=$((~mask & 0xFFFFFFFF))
dec_to_ip $((ip_dec | wildcard))
}
# Get first usable host
first_host() {
local net=$(network_addr "$1" "$2")
local net_dec=$(ip_to_dec "$net")
dec_to_ip $((net_dec + 1))
}
# Get last usable host
last_host() {
local bcast=$(broadcast_addr "$1" "$2")
local bcast_dec=$(ip_to_dec "$bcast")
dec_to_ip $((bcast_dec - 1))
}
# Full subnet info
subnet_info() {
local ip=$1 cidr=$2
echo "IP Address: $ip/$cidr"
echo "Subnet Mask: $(cidr_to_mask $cidr)"
echo "Network: $(network_addr $ip $cidr)"
echo "Broadcast: $(broadcast_addr $ip $cidr)"
echo "First Host: $(first_host $ip $cidr)"
echo "Last Host: $(last_host $ip $cidr)"
echo "Total Hosts: $((2 ** (32 - cidr)))"
echo "Usable Hosts: $((2 ** (32 - cidr) - 2))"
}
# Example usage:
subnet_info "192.168.1.100" 26
Output:
IP Address: 192.168.1.100/26 Subnet Mask: 255.255.255.192 Network: 192.168.1.64 Broadcast: 192.168.1.127 First Host: 192.168.1.65 Last Host: 192.168.1.126 Total Hosts: 64 Usable Hosts: 62
VLSM (Variable Length Subnet Masking)
Divide a network into different sized subnets based on need.
# Given: 192.168.1.0/24, need subnets for:
# - 50 hosts (needs /26 = 62 usable)
# - 25 hosts (needs /27 = 30 usable)
# - 10 hosts (needs /28 = 14 usable)
# - 2 hosts (needs /30 = 2 usable, point-to-point)
# Find minimum CIDR for N hosts
cidr_for_hosts() {
local hosts=$1
for cidr in {32..0}; do
usable=$((2 ** (32 - cidr) - 2))
[[ $usable -ge $hosts ]] && { echo $cidr; return; }
done
}
echo "50 hosts needs: /$(cidr_for_hosts 50)" # /26
echo "25 hosts needs: /$(cidr_for_hosts 25)" # /27
echo "10 hosts needs: /$(cidr_for_hosts 10)" # /28
echo "2 hosts needs: /$(cidr_for_hosts 2)" # /30
# VLSM allocation (largest first!)
# Start: 192.168.1.0/24
#
# Subnet 1: /26 (50 hosts) → 192.168.1.0/26 (0-63)
# Subnet 2: /27 (25 hosts) → 192.168.1.64/27 (64-95)
# Subnet 3: /28 (10 hosts) → 192.168.1.96/28 (96-111)
# Subnet 4: /30 (2 hosts) → 192.168.1.112/30 (112-115)
# Remaining: 192.168.1.116 - 192.168.1.255 (unused)
Supernetting (Route Aggregation)
Combine contiguous networks into one summary route.
# Given four /24 networks:
# 192.168.0.0/24
# 192.168.1.0/24
# 192.168.2.0/24
# 192.168.3.0/24
#
# Can they be summarized? Check if contiguous and power of 2.
# Binary analysis:
# 192.168.0.0 = 11000000.10101000.00000000.00000000
# 192.168.1.0 = 11000000.10101000.00000001.00000000
# 192.168.2.0 = 11000000.10101000.00000010.00000000
# 192.168.3.0 = 11000000.10101000.00000011.00000000
#
# First 22 bits identical → Summary: 192.168.0.0/22
# Verify:
echo "192.168.0.0/22 covers:"
for i in {0..3}; do
echo " 192.168.$i.0/24"
done
# Calculate supernet prefix
# 4 networks = 2^2, so subtract 2 from original CIDR
# /24 - 2 = /22
Check if IP is in Subnet
# Is IP in subnet?
ip_in_subnet() {
local ip=$1 network=$2 cidr=$3
local ip_dec=$(ip_to_dec "$ip")
local net_dec=$(ip_to_dec "$network")
local mask=$(( (0xFFFFFFFF << (32 - cidr)) & 0xFFFFFFFF ))
[[ $((ip_dec & mask)) -eq $((net_dec & mask)) ]]
}
# Example
if ip_in_subnet "192.168.1.100" "192.168.1.0" 24; then
echo "192.168.1.100 IS in 192.168.1.0/24"
fi
if ! ip_in_subnet "192.168.2.1" "192.168.1.0" 24; then
echo "192.168.2.1 is NOT in 192.168.1.0/24"
fi
Data Units (Bytes)
SI (decimal) vs IEC (binary):
| SI Unit | Value | IEC Unit | Value |
|---|---|---|---|
KB (kilobyte) |
10³ = 1,000 |
KiB (kibibyte) |
2¹⁰ = 1,024 |
MB (megabyte) |
10⁶ = 1,000,000 |
MiB (mebibyte) |
2²⁰ = 1,048,576 |
GB (gigabyte) |
10⁹ |
GiB (gibibyte) |
2³⁰ |
TB (terabyte) |
10¹² |
TiB (tebibyte) |
2⁴⁰ |
# Bytes to human-readable (IEC - what computers actually use)
bytes_to_human() {
local bytes=$1
local units=("B" "KiB" "MiB" "GiB" "TiB" "PiB")
local unit=0
local size=$bytes
while [[ $(echo "$size >= 1024" | bc) -eq 1 ]] && [[ $unit -lt 5 ]]; do
size=$(echo "scale=2; $size / 1024" | bc)
((unit++))
done
echo "$size ${units[$unit]}"
}
bytes_to_human 1073741824 # 1.00 GiB
bytes_to_human 1500000000 # 1.39 GiB
# Human to bytes
human_to_bytes() {
local input=$1
local num=${input%[KMGTP]*}
local unit=${input##*[0-9]}
case $unit in
K|KB) echo $((num * 1000)) ;;
KiB) echo $((num * 1024)) ;;
M|MB) echo $((num * 1000000)) ;;
MiB) echo $((num * 1024 * 1024)) ;;
G|GB) echo $((num * 1000000000)) ;;
GiB) echo $((num * 1024 * 1024 * 1024)) ;;
*) echo $num ;;
esac
}
human_to_bytes "4GiB" # 4294967296
Network Speed Units
Bits vs Bytes: Network = bits/sec, Storage = bytes/sec
# bits per second to bytes per second
# Divide by 8 (8 bits = 1 byte)
bps_to_Bps() {
echo $(($1 / 8))
}
# Mbps to MiB/s (practical download speed)
mbps_to_mibs() {
local mbps=$1
# Mbps = millions of bits per second (SI)
# To MiB/s: (mbps × 1,000,000) / 8 / 1,048,576
echo "scale=2; $mbps * 1000000 / 8 / 1048576" | bc
}
echo "100 Mbps = $(mbps_to_mibs 100) MiB/s" # 11.92 MiB/s
echo "1000 Mbps = $(mbps_to_mibs 1000) MiB/s" # 119.20 MiB/s
# Download time calculator
download_time() {
local size_mib=$1
local speed_mbps=$2
local speed_mibs=$(mbps_to_mibs $speed_mbps)
echo "scale=2; $size_mib / $speed_mibs" | bc
}
echo "4000 MiB at 100 Mbps: $(download_time 4000 100) seconds"
Time Conversions
# Seconds to human readable
seconds_to_human() {
local secs=$1
local days=$((secs / 86400))
local hours=$(( (secs % 86400) / 3600 ))
local mins=$(( (secs % 3600) / 60 ))
local s=$((secs % 60))
[[ $days -gt 0 ]] && printf "%dd " $days
[[ $hours -gt 0 ]] && printf "%dh " $hours
[[ $mins -gt 0 ]] && printf "%dm " $mins
printf "%ds\n" $s
}
seconds_to_human 90061 # 1d 1h 1m 1s
# Human to seconds
human_to_seconds() {
local input=$1 total=0
[[ $input =~ ([0-9]+)d ]] && total=$((total + BASH_REMATCH[1] * 86400))
[[ $input =~ ([0-9]+)h ]] && total=$((total + BASH_REMATCH[1] * 3600))
[[ $input =~ ([0-9]+)m ]] && total=$((total + BASH_REMATCH[1] * 60))
[[ $input =~ ([0-9]+)s ]] && total=$((total + BASH_REMATCH[1]))
echo $total
}
human_to_seconds "2d 3h 15m" # 183300
# Epoch timestamps
date +%s # Current epoch
date -d @1709337600 # Epoch to date
date -d "2024-03-01" +%s # Date to epoch
Scientific Notation
# Large numbers in scientific notation
printf "%e\n" 1234567890 # 1.234568e+09
printf "%.2e\n" 6022000000000000000000000 # 6.02e+23 (Avogadro-ish)
# bc for precision
echo "scale=10; 6.022 * 10^23" | bc # 6022000000000000000000000.0000000000
# awk for scientific
awk 'BEGIN { printf "%.3e\n", 299792458 }' # 2.998e+08 (speed of light m/s)
# Engineering notation (powers of 3)
eng_notation() {
local n=$1
python3 -c "
from decimal import Decimal
d = Decimal('$n')
print(d.normalize().to_eng_string())
"
}
eng_notation 1500000 # 1.5E+6
eng_notation 0.000001 # 1E-6
Memory Calculations (RAM, Disk)
# Check system memory
free -b | awk '/^Mem:/ {print "Total RAM:", $2, "bytes"}'
free -h | awk '/^Mem:/ {print "Total RAM:", $2}'
# Disk space in bytes
df -B1 / | awk 'NR==2 {print "Root disk:", $2, "bytes"}'
# Page size (memory alignment)
getconf PAGESIZE # Usually 4096 (4 KiB)
# Calculate pages needed for N bytes
pages_needed() {
local bytes=$1
local page_size=$(getconf PAGESIZE)
echo $(( (bytes + page_size - 1) / page_size ))
}
pages_needed 10000 # 3 pages (for 10000 bytes)
# RAM for processes
ps aux --sort=-%mem | head -5 | awk '{print $4"% "$11}'
Quick Unit Reference
| Category | Conversions | Formula |
|---|---|---|
Bytes |
1 KiB = 1024 B |
2^10 |
1 MiB = 1024 KiB |
2^20 B |
|
1 GiB = 1024 MiB |
2^30 B |
|
Network |
1 byte = 8 bits |
bps / 8 = Bps |
Mbps → MiB/s |
× 10⁶ / 8 / 2²⁰ |
|
Time |
1 day = 86400 s |
24 × 60 × 60 |
1 hour = 3600 s |
60 × 60 |
|
IPv4 |
1 octet = 8 bits |
0-255 |
IP = 32 bits |
4 × 8 |
|
Hex |
1 byte = 2 hex digits |
FF = 255 |
1 nibble = 1 hex digit |
F = 15 |
12. Pattern Syntax (Brace vs Regex vs Glob)
CRITICAL: Shell has THREE different pattern systems. Don’t mix them!
The Three Pattern Languages
CRITICAL: Shell has THREE different pattern systems. Don’t mix them!
| Type | Syntax | Expansion | Example |
|---|---|---|---|
Brace |
|
Shell expands BEFORE command runs |
|
Glob |
|
Shell matches existing files |
|
Regex |
|
Used by grep, sed, awk INSIDE strings |
|
# WRONG - mixing regex alternation with shell
ls 02_Assets/LRN-COLLEGE-ALGEBRA-(L|Q|T)*
# zsh: no matches found (unless extendedglob is set)
# CORRECT - brace expansion
ls 02_Assets/LRN-COLLEGE-ALGEBRA-{LATEX,PANDOC,QUARTO,TYPST}
# Expands to 4 separate arguments
# CORRECT - glob with wildcard
ls -d 02_Assets/LRN-COLLEGE-ALGEBRA-*/
# Matches any directory starting with that prefix
# Brace + glob COMBINED (powerful!)
ls src/{main,test}/**/*.{js,ts}
# Braces expand first, then globs match
Key insight: Braces expand to MULTIPLE ARGUMENTS before the command sees them. Globs match EXISTING FILES. Regex only works inside tools like grep/sed.
Extended Glob (zsh/bash)
Enable regex-like patterns in glob context.
# Bash: enable extended glob
shopt -s extglob
# Zsh: enable extended glob
setopt EXTENDED_GLOB
# Extended glob patterns (bash extglob):
# ?(pattern) - 0 or 1 match
# *(pattern) - 0 or more matches
# +(pattern) - 1 or more matches
# @(pattern) - exactly 1 match
# !(pattern) - NOT matching
# Example: match .js OR .ts files
ls *.@(js|ts)
# Zsh extended glob uses different syntax:
# (#i) - case insensitive
# (pattern~except) - except
# pattern(/) - directories only
ls LRN-COLLEGE-ALGEBRA-*(/) # directories only
Math Rendering Ecosystem
| Tool | Best For | Output | Learn |
|---|---|---|---|
LaTeX |
Academic papers, formal proofs |
PDF (pdflatex, xelatex, lualatex) |
High |
Typst |
Modern LaTeX replacement, fast |
Medium |
|
MathJax |
Web display (docs, wikis) |
HTML (JavaScript rendered) |
Low |
AsciiDoc :stem: |
Technical docs (uses MathJax) |
HTML, PDF |
Low |
Jupyter |
Interactive notebooks |
HTML, PDF |
Medium |
For your workflow:
-
Antora docs:
:stem: latexmath(MathJax) -
Formal papers: LaTeX or Typst
-
Quick notes: AsciiDoc or Markdown with MathJax
LaTeX from Command Line
# Compile LaTeX to PDF
pdflatex document.tex # Basic
xelatex document.tex # Better Unicode support
lualatex document.tex # Lua scripting
# One-liner math rendering (requires standalone class)
cat << 'EOF' > /tmp/math.tex
\documentclass{standalone}
\usepackage{amsmath}
\begin{document}
$E = mc^2$
\end{document}
EOF
pdflatex -output-directory=/tmp /tmp/math.tex
# Convert to PNG for embedding
pdftoppm -png /tmp/math.pdf /tmp/math
# Result: /tmp/math-1.png
# Quick equation check (latexmk for automation)
latexmk -pdf -pvc document.tex # Auto-recompile on save
Common LaTeX math:
% Fractions
\frac{a}{b}
% Subscript/superscript
x^2, x_i, x_i^2
% Greek letters
\alpha, \beta, \gamma, \pi, \sigma, \theta
% Summation, integral
\sum_{i=1}^{n} x_i
\int_{0}^{\infty} e^{-x} dx
% Matrices
\begin{pmatrix} a & b \\ c & d \end{pmatrix}
% Align equations
\begin{align}
f(x) &= ax^2 + bx + c \\
&= a(x - h)^2 + k
\end{align}
Typst - Modern LaTeX Alternative
Faster compilation, cleaner syntax, better error messages.
# Install typst
pacman -S typst # Arch
brew install typst # macOS
# Compile
typst compile document.typ
typst compile document.typ output.pdf
# Watch mode (auto-recompile)
typst watch document.typ
# One-liner
echo '$ E = m c^2 $' | typst compile - output.pdf
Typst math syntax:
// Fractions (natural!)
$ a/b $
// Subscript/superscript
$ x^2, x_i, x_i^2 $
// Greek (just type them!)
$ alpha, beta, gamma, pi $
// Summation
$ sum_(i=1)^n x_i $
// Matrices
$ mat(a, b; c, d) $
// Align
$ f(x) &= a x^2 + b x + c \
&= a(x - h)^2 + k $
Typst vs LaTeX:
| Feature | LaTeX | Typst |
|---|---|---|
Compile speed |
Slow |
Fast (100x) |
Error messages |
Cryptic |
Clear |
Learning curve |
Steep |
Gentle |
Package ecosystem |
Massive |
Growing |
PDF quality |
Excellent |
Excellent |
AsciiDoc Math (MathJax/STEM)
For Antora documentation.
= Document with Math
:stem: latexmath
Inline math: stem:[E = mc^2]
Block math:
[stem]
++++
\sum_{i=1}^{n} x_i = \frac{n(n+1)}{2}
++++
The quadratic formula:
[stem]
++++
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
++++
Build with Antora:
# Local build (Kroki handles diagrams)
cd domus-docs && make
# The :stem: attribute enables MathJax rendering
# MathJax loads from CDN in browser
Maxima - Computer Algebra System
Free, powerful symbolic math (like Mathematica).
# Install
pacman -S maxima wxmaxima # Arch (wxmaxima = GUI)
apt install maxima wxmaxima # Debian
# CLI usage
maxima --batch-string="diff(x^3 + 2*x, x);"
# Output: 3*x^2 + 2
maxima --batch-string="integrate(sin(x), x);"
# Output: -cos(x)
maxima --batch-string="factor(x^2 - 4);"
# Output: (x - 2)*(x + 2)
maxima --batch-string="solve(x^2 + 2*x - 3 = 0, x);"
# Output: [x = -3, x = 1]
# Limit
maxima --batch-string="limit(sin(x)/x, x, 0);"
# Output: 1
# Taylor series
maxima --batch-string="taylor(exp(x), x, 0, 5);"
# Output: 1 + x + x^2/2 + x^3/6 + x^4/24 + x^5/120 + ...
Interactive session:
$ maxima
Maxima 5.46.0
(%i1) f: x^3 - 6*x^2 + 11*x - 6;
(%o1) x^3 - 6*x^2 + 11*x - 6
(%i2) factor(f);
(%o2) (x - 1)*(x - 2)*(x - 3)
(%i3) diff(f, x);
(%o3) 3*x^2 - 12*x + 11
(%i4) integrate(f, x);
(%o4) x^4/4 - 2*x^3 + 11*x^2/2 - 6*x
SymPy - Python Symbolic Math
# Install
pip install sympy
# One-liners
python3 -c "from sympy import *; x = Symbol('x'); print(diff(x**3, x))"
# Output: 3*x**2
python3 -c "from sympy import *; x = Symbol('x'); print(integrate(sin(x), x))"
# Output: -cos(x)
python3 -c "from sympy import *; x = Symbol('x'); print(factor(x**2 - 4))"
# Output: (x - 2)*(x + 2)
python3 -c "from sympy import *; x = Symbol('x'); print(solve(x**2 + 2*x - 3, x))"
# Output: [-3, 1]
# Pretty printing
python3 -c "
from sympy import *
init_printing()
x = Symbol('x')
expr = integrate(exp(-x**2), x)
pprint(expr)
"
# LaTeX output (for docs!)
python3 -c "from sympy import *; x = Symbol('x'); print(latex(Integral(exp(-x**2), x)))"
# Output: \int e^{- x^{2}}\, dx
gnuplot - The Classic
# Install
pacman -S gnuplot # Arch
# Quick plot to terminal (ASCII art!)
gnuplot -e "set terminal dumb; plot sin(x)"
# Plot to PNG
gnuplot << 'EOF'
set terminal png size 800,600
set output 'plot.png'
set title 'Quadratic Function'
set xlabel 'x'
set ylabel 'f(x)'
plot x**2 - 4*x + 3 title 'x^2 - 4x + 3' with lines
EOF
# Plot data from file
echo -e "1 1\n2 4\n3 9\n4 16\n5 25" > /tmp/data.txt
gnuplot -e "set terminal dumb; plot '/tmp/data.txt' with linespoints"
# Multiple functions
gnuplot << 'EOF'
set terminal png size 800,600
set output 'trig.png'
set title 'Trigonometric Functions'
plot sin(x), cos(x), tan(x) title 'tan(x)'
EOF
# Parametric (circle)
gnuplot << 'EOF'
set terminal dumb
set parametric
set trange [0:2*pi]
plot sin(t), cos(t)
EOF
matplotlib - Python Plotting
# Install
pip install matplotlib numpy
# Quick plot
python3 << 'EOF'
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-10, 10, 100)
y = x**2 - 4*x + 3
plt.figure(figsize=(8, 6))
plt.plot(x, y, label='$f(x) = x^2 - 4x + 3$')
plt.axhline(y=0, color='k', linestyle='-', linewidth=0.5)
plt.axvline(x=0, color='k', linestyle='-', linewidth=0.5)
plt.grid(True, alpha=0.3)
plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('Quadratic Function')
plt.legend()
plt.savefig('quadratic.png', dpi=150)
print('Saved: quadratic.png')
EOF
# Unit circle
python3 << 'EOF'
import matplotlib.pyplot as plt
import numpy as np
theta = np.linspace(0, 2*np.pi, 100)
x = np.cos(theta)
y = np.sin(theta)
plt.figure(figsize=(6, 6))
plt.plot(x, y)
plt.axis('equal')
plt.grid(True)
plt.title('Unit Circle')
plt.savefig('unit_circle.png', dpi=150)
EOF
Terminal Plotting (No GUI)
# Using gnuplot dumb terminal
plot_term() {
gnuplot -e "set terminal dumb size 60,20; plot $1"
}
plot_term "sin(x)"
plot_term "x**2"
# Using Python with termgraph (pip install termgraph)
echo -e "A 10\nB 25\nC 15\nD 30" | termgraph
# Sparklines with spark (npm install -g spark)
echo "1 5 22 13 53" | spark
# Output: ▁▁▃▂█
# Using plotext (pip install plotext)
python3 << 'EOF'
import plotext as plt
import numpy as np
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
plt.plot(x, y)
plt.title("Sine Wave (Terminal)")
plt.show()
EOF
GNU Octave - MATLAB Compatible
# Install
pacman -S octave # Arch
# Matrix operations
octave --eval "A = [1 2; 3 4]; B = [5 6; 7 8]; A * B"
# Output:
# 19 22
# 43 50
# Determinant
octave --eval "A = [1 2; 3 4]; det(A)"
# Output: -2
# Inverse
octave --eval "A = [1 2; 3 4]; inv(A)"
# Output:
# -2.0000 1.0000
# 1.5000 -0.5000
# Eigenvalues
octave --eval "A = [4 2; 1 3]; eig(A)"
# Output:
# 2
# 5
# Solve linear system Ax = b
octave --eval "A = [2 1; 1 3]; b = [5; 10]; x = A \\ b"
# Output:
# 1
# 3
# (2*1 + 1*3 = 5, 1*1 + 3*3 = 10) ✓
# Matrix rank, null space
octave --eval "A = [1 2 3; 4 5 6; 7 8 9]; rank(A)"
# Output: 2 (not full rank!)
NumPy - Python Linear Algebra
# Install
pip install numpy
# Matrix multiplication
python3 -c "
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(A @ B) # Matrix multiply
"
# Determinant, inverse, eigenvalues
python3 << 'EOF'
import numpy as np
from numpy.linalg import det, inv, eig
A = np.array([[4, 2], [1, 3]])
print(f"Determinant: {det(A)}")
print(f"Inverse:\n{inv(A)}")
eigenvalues, eigenvectors = eig(A)
print(f"Eigenvalues: {eigenvalues}")
print(f"Eigenvectors:\n{eigenvectors}")
EOF
# Solve Ax = b
python3 -c "
import numpy as np
A = np.array([[2, 1], [1, 3]])
b = np.array([5, 10])
x = np.linalg.solve(A, b)
print(f'Solution: x = {x}')
# Verify: A @ x should equal b
print(f'Verification: A @ x = {A @ x}')
"
SciPy, NumPy, SymPy, Matplotlib
The complete scientific computing environment.
# Install the stack
pip install numpy scipy sympy matplotlib pandas jupyter
# Check versions
python3 -c "
import numpy, scipy, sympy, matplotlib
print(f'NumPy: {numpy.__version__}')
print(f'SciPy: {scipy.__version__}')
print(f'SymPy: {sympy.__version__}')
print(f'Matplotlib: {matplotlib.__version__}')
"
Use cases:
| Package | Purpose |
|---|---|
NumPy |
Arrays, linear algebra, FFT |
SciPy |
Integration, optimization, statistics, signal processing |
SymPy |
Symbolic math (differentiation, integration, solving) |
Matplotlib |
Plotting and visualization |
Pandas |
Data frames, time series, CSV handling |
Jupyter |
Interactive notebooks |
Numerical Calculus with SciPy
# Numerical integration
python3 -c "
from scipy import integrate
import numpy as np
# Integrate sin(x) from 0 to pi
result, error = integrate.quad(np.sin, 0, np.pi)
print(f'∫₀^π sin(x) dx = {result:.6f}')
# Output: 2.000000
# Integrate x^2 from 0 to 1
result, error = integrate.quad(lambda x: x**2, 0, 1)
print(f'∫₀^1 x² dx = {result:.6f}')
# Output: 0.333333 (= 1/3)
"
# Numerical differentiation
python3 -c "
from scipy.misc import derivative
import numpy as np
f = lambda x: x**3
# Derivative at x=2
df = derivative(f, 2, dx=1e-6)
print(f\"f(x) = x³, f'(2) = {df:.6f}\")
# Output: 12.000000 (3 * 2² = 12)
"
# Root finding
python3 -c "
from scipy.optimize import fsolve
import numpy as np
# Solve x³ - x - 2 = 0
f = lambda x: x**3 - x - 2
root = fsolve(f, 1.5) # Initial guess
print(f'Root of x³ - x - 2 = 0: x = {root[0]:.6f}')
"
Statistics with SciPy
# Descriptive statistics
python3 << 'EOF'
import numpy as np
from scipy import stats
data = [23, 45, 67, 32, 89, 12, 56, 78, 34, 91]
print(f"Mean: {np.mean(data):.2f}")
print(f"Median: {np.median(data):.2f}")
print(f"Std Dev: {np.std(data):.2f}")
print(f"Variance: {np.var(data):.2f}")
# Mode
mode_result = stats.mode(data)
print(f"Mode: {mode_result.mode}")
EOF
# Normal distribution
python3 -c "
from scipy.stats import norm
# P(X < 1.96) for standard normal
p = norm.cdf(1.96)
print(f'P(Z < 1.96) = {p:.4f}') # ~0.975
# Find z-score for 95th percentile
z = norm.ppf(0.95)
print(f'95th percentile z-score: {z:.4f}') # ~1.645
"
# Hypothesis testing
python3 -c "
from scipy import stats
# Two-sample t-test
group1 = [23, 25, 28, 30, 32]
group2 = [18, 22, 25, 27, 30]
t_stat, p_value = stats.ttest_ind(group1, group2)
print(f't-statistic: {t_stat:.4f}')
print(f'p-value: {p_value:.4f}')
"
Next Steps
All tools covered above are ready to use. Your workflow:
-
Antora docs:
:stem: latexmath(MathJax renders in browser) -
Formal papers: LaTeX or Typst
-
Interactive: Jupyter notebooks
-
Quick calculations: bc, awk, python one-liners
Low-level path:
-
C: Direct memory, pointers, bit manipulation
-
Rust: Safe systems programming with zero-cost abstractions
-
Assembly: x86_64 for understanding CPU instructions
-
Kernel:
/usr/src/linux- read the networking stack