1. What Is Linux?

Linux is an operating system kernel -- the core piece of software that talks to your hardware (CPU, RAM, disk, GPU) and lets programs run on top of it. It was created in 1991 by Linus Torvalds, a Finnish computer science student, as a free alternative to the expensive Unix operating systems that universities and companies used.

When people say "Linux" they usually mean a complete operating system built around the Linux kernel. Technically, the full stack is:

┌─────────────────────────────────────┐ │ Your Applications │ ← Firefox, VS Code, terminal, etc. │ (GUI apps, CLI tools, scripts) │ ├─────────────────────────────────────┤ │ Desktop Environment │ ← COSMIC (Pop!_OS), GNOME, KDE │ (window manager, panels, themes) │ ├─────────────────────────────────────┤ │ System Libraries & Utilities │ ← GNU coreutils, glibc, systemd │ (ls, cp, cat, bash, apt, etc.) │ ├─────────────────────────────────────┤ │ Linux Kernel │ ← The actual "Linux" part │ (process mgmt, memory, drivers, │ │ filesystems, networking) │ ├─────────────────────────────────────┤ │ Hardware │ ← CPU, RAM, SSD, GPU, NIC └─────────────────────────────────────┘

The kernel alone isn't useful -- you need all the tools around it (shell, file utilities, package manager, display server) to have a working system. That's why some people call it GNU/Linux -- because most of those utilities come from the GNU project (started by Richard Stallman in 1983).

Why Linux Matters for Developers

  • Servers run Linux -- over 96% of the world's top web servers run Linux. If you deploy code, you're deploying to Linux.
  • It's open source -- you can read the kernel source code, modify it, and understand exactly what your computer is doing. No black boxes.
  • The terminal is first-class -- unlike Windows where the terminal is an afterthought, Linux was built around the command line. Most development tools assume a Unix-like environment.
  • Containers are Linux -- Docker, Kubernetes, and all container tech runs on the Linux kernel (namespaces + cgroups).
  • It's free -- no license costs, no activation keys, no forced updates.
Open Source Means You Can Learn

Every command you run on Linux is open source. Curious how ls works? You can read the actual C source code. Wondering what apt does when it installs a package? You can read the Python source. This is incredibly powerful for learning.

2. Unix vs Linux

You'll hear "Unix" and "Linux" used interchangeably, but they're different things with a shared history.

The History (Quick Version)

  1. 1969 -- Ken Thompson and Dennis Ritchie create Unix at AT&T Bell Labs. It's written in C (which Ritchie also created). Unix introduces revolutionary ideas: "everything is a file", pipes, a hierarchical filesystem, and the shell.
  2. 1970s-80s -- Unix spreads to universities. Different versions appear: BSD (Berkeley), System V (AT&T), SunOS, HP-UX, AIX. Each is proprietary and expensive.
  3. 1983 -- Richard Stallman starts the GNU project to create a free Unix-like system. He builds all the user-space tools (compiler, shell, utilities) but the kernel (GNU Hurd) is never finished.
  4. 1991 -- Linus Torvalds writes the Linux kernel as a hobby project. Combined with GNU tools, it becomes a complete free Unix-like operating system.
  5. Today -- Linux dominates servers, phones (Android), embedded devices, supercomputers (100% of the top 500), and is increasingly popular on desktops.

Key Differences

AspectUnixLinux
OriginAT&T Bell Labs, 1969Linus Torvalds, 1991
LicenseProprietary (mostly)GPL (free and open source)
Source codeClosed (mostly)Fully open
CostExpensive licensesFree
ExamplesmacOS, Solaris, HP-UX, AIXUbuntu, Fedora, Pop!_OS, Arch, Debian
KernelVarious (XNU for macOS, etc.)Linux kernel
HardwareOften tied to specific hardwareRuns on almost anything
POSIXCertified POSIX compliantMostly POSIX compliant (not certified)

Unix-like vs Unix

Linux is Unix-like -- it behaves like Unix, follows similar conventions, and programs written for Unix usually work on Linux. But it's not Unix. It doesn't share any code with the original AT&T Unix. It was written from scratch.

macOS is actually certified Unix. Under the hood, macOS runs a Unix kernel called XNU (derived from BSD). That's why the macOS terminal feels similar to Linux -- they share Unix roots.

POSIX -- The Standard

POSIX (Portable Operating System Interface) is a set of standards that defines how a Unix-like operating system should behave. It specifies things like:

  • What system calls must exist (open, read, write, fork, exec...)
  • How the shell should work
  • What utilities must be available (ls, grep, awk, sed...)
  • How regular expressions work

Both Unix systems and Linux follow POSIX (mostly). This is why shell scripts and command-line tools work across different Unix-like systems.

Key Takeaway

Linux is a free, open-source reimplementation of Unix ideas. It's not Unix, but it works like Unix. When a tutorial says "Unix/Linux" or "POSIX", the commands will work on your Pop!_OS system.

3. Linux Distros & Pop!_OS

A Linux distribution (distro) is a complete operating system built around the Linux kernel. Different distros package different software, use different package managers, and target different users. But they all share the same kernel.

The Family Tree

Linux Kernel │ ├── Debian ─────────── Ubuntu ─────── Pop!_OS ← YOU ARE HERE │ │ │ ├── Linux Mint │ └── Elementary OS │ ├── Red Hat (RHEL) ──── Fedora │ │ │ └── CentOS / Rocky Linux │ ├── Arch Linux ─────── Manjaro │ └── EndeavourOS │ ├── SUSE ───────────── openSUSE │ ├── Gentoo │ └── Slackware (oldest active distro)

Major Distro Families

FamilyPackage ManagerPackage FormatNotable Distros
Debianapt / dpkg.debDebian, Ubuntu, Pop!_OS, Mint
Red Hatdnf / rpm.rpmFedora, RHEL, CentOS, Rocky
Archpacman.pkg.tar.zstArch, Manjaro, EndeavourOS
SUSEzypper / rpm.rpmopenSUSE Tumbleweed/Leap

Your Distro: Pop!_OS

Pop!_OS is made by System76, a company that builds Linux laptops and desktops. Here's what makes it special:

  • Based on Ubuntu -- which is based on Debian. So you can use apt to install packages, and most Ubuntu tutorials work on Pop!_OS.
  • COSMIC desktop -- System76 built their own desktop environment. It has auto-tiling windows, a clean design, and is written in Rust.
  • Pop!_Shop -- a graphical app store (Flatpak-based) for installing software.
  • Built for developers -- comes with good defaults, GPU switching for NVIDIA/AMD, and recovery partition.
  • systemd-boot -- uses systemd-boot instead of GRUB as the bootloader (simpler and faster).

To check your system info:

Shell
# What distro are you running?
$ cat /etc/os-release
NAME="Pop!_OS"
VERSION="22.04 LTS"
ID=pop
ID_LIKE="ubuntu debian"

# What kernel version?
$ uname -r
6.17.9-76061709-generic

# System architecture
$ uname -m
x86_64

# All system info in one shot
$ hostnamectl
Ubuntu Compatibility

Since Pop!_OS is based on Ubuntu, you can use Ubuntu PPAs, Ubuntu tutorials, and Ubuntu .deb packages. If you're searching for how to do something, search "Ubuntu" + your question -- it will almost always work on Pop!_OS too.

4. The Kernel

The kernel is the core of the operating system. It's the one piece of software that runs in kernel mode (privileged mode) with full access to hardware. Everything else -- your browser, your terminal, your text editor -- runs in user mode and must ask the kernel for permission to do anything hardware-related.

What the Kernel Does

THE LINUX KERNEL ┌─────────────────────────────────────────────┐ │ │ │ Process Management │ │ ├── Create/destroy processes (fork/exit) │ │ ├── Schedule which process runs next │ │ └── Context switching between processes │ │ │ │ Memory Management │ │ ├── Virtual memory (page tables) │ │ ├── Allocate/free physical memory │ │ └── Swap pages to/from disk │ │ │ │ Device Drivers │ │ ├── Talk to hardware (GPU, NIC, USB) │ │ ├── Expose devices as files in /dev │ │ └── Handle interrupts from devices │ │ │ │ File Systems │ │ ├── ext4, btrfs, xfs, ntfs, fat32 │ │ ├── Virtual filesystems (/proc, /sys) │ │ └── File permissions enforcement │ │ │ │ Networking │ │ ├── TCP/IP stack │ │ ├── Socket API │ │ ├── Firewall (netfilter/iptables) │ │ └── Network device drivers │ │ │ │ Security │ │ ├── User/group permissions │ │ ├── Namespaces (containers) │ │ ├── cgroups (resource limits) │ │ └── SELinux/AppArmor │ │ │ └─────────────────────────────────────────────┘

How Programs Talk to the Kernel

Programs can't call kernel functions directly. They use system calls (syscalls) -- a special CPU instruction that switches from user mode to kernel mode. When you call open(), read(), write(), fork(), etc., you're making syscalls. (See the OS page section on syscalls for the full details.)

Shell
# See kernel version
$ uname -r
6.17.9-76061709-generic

# See kernel messages (hardware detection, driver loading, errors)
$ dmesg | tail -20

# See loaded kernel modules (drivers)
$ lsmod

# Kernel configuration
$ cat /boot/config-$(uname -r) | head

# See kernel parameters
$ sysctl -a | head

Monolithic vs Microkernel

Linux is a monolithic kernel -- all the core services (process management, file systems, device drivers, networking) run in kernel space. This is fast because there's no overhead of message passing between components.

The alternative is a microkernel (like GNU Hurd or MINIX) where only the bare minimum runs in kernel mode and everything else runs as user-space servers. More secure and modular, but slower due to inter-process communication overhead.

Linux uses loadable kernel modules as a middle ground -- drivers can be loaded and unloaded at runtime without rebooting:

Shell
# List loaded modules
$ lsmod

# Info about a module
$ modinfo nvidia

# Load a module (requires sudo)
$ sudo modprobe module_name

# Unload a module
$ sudo rmmod module_name
The Kernel Is Not the OS

The kernel is just one part of the operating system. It manages hardware and provides services. But without a shell, file utilities, a package manager, and a desktop environment, a kernel alone is useless. That's what distros provide -- everything around the kernel to make a usable system.

5. The Shell

The shell is a program that reads commands you type, interprets them, and asks the kernel to execute them. It's the text-based interface between you and the operating system. When you open a terminal on Pop!_OS, the shell is the program running inside it.

How the Shell Works

You type: ls -la /home ┌──────────────┐ │ Terminal │ ← The window (GUI application) │ Emulator │ (e.g., GNOME Terminal, Alacritty) └──────┬───────┘ │ sends keystrokes ▼ ┌──────────────┐ │ Shell │ ← The interpreter (e.g., bash, zsh) │ (bash) │ Parses "ls -la /home" └──────┬───────┘ │ fork() + exec("ls", "-la", "/home") ▼ ┌──────────────┐ │ Kernel │ ← Creates process, runs ls binary └──────┬───────┘ │ ls reads directory, writes to stdout ▼ Output appears in your terminal

The shell is NOT the terminal. The terminal emulator is the GUI window. The shell is the program running inside it that actually processes your commands.

Common Shells

ShellBinaryNotes
bash/bin/bashBourne Again Shell. Default on most Linux distros including Pop!_OS. The one you should learn first.
zsh/bin/zshZ Shell. Default on macOS. More features than bash (better autocomplete, themes). Compatible with bash mostly.
fish/usr/bin/fishFriendly Interactive Shell. Great autosuggestions and syntax highlighting out of the box. NOT bash-compatible.
sh/bin/shBourne Shell (POSIX shell). Minimal. Used for scripts that need maximum portability.
dash/bin/dashDebian Almquist Shell. What /bin/sh points to on Debian/Ubuntu/Pop!_OS. Very fast, minimal.
Shell
# What shell am I using?
$ echo $SHELL
/bin/bash

# What shells are installed?
$ cat /etc/shells

# Change your default shell to zsh
$ chsh -s /bin/zsh

# Temporarily use a different shell
$ zsh        # starts zsh session
$ exit       # back to previous shell

Shell Features You Should Know

Tab Completion

Press Tab to autocomplete commands, file names, and paths. Press Tab twice to see all possibilities. This is the single most important productivity feature. Stop typing full file names.

Command History

Shell
# Search history (most useful shortcut in bash)
Ctrl+R  then type part of a previous command

# Show recent commands
$ history | tail -20

# Re-run the last command
$ !!

# Re-run last command starting with "git"
$ !git

# Run previous command with sudo
$ sudo !!

Pipes and Redirection

This is the fundamental Unix philosophy: small programs that do one thing well, connected together with pipes.

Shell
# Pipe: send stdout of one command to stdin of another
$ ls -la | grep ".txt"           # list files, filter for .txt
$ cat log.txt | sort | uniq -c   # count unique lines
$ ps aux | grep firefox          # find firefox processes

# Redirect stdout to a file (overwrites)
$ echo "hello" > output.txt

# Redirect stdout to a file (appends)
$ echo "world" >> output.txt

# Redirect stderr to a file
$ ./my_script 2> errors.txt

# Redirect both stdout and stderr
$ ./my_script > output.txt 2>&1

# Discard output (send to /dev/null -- the void)
$ ./noisy_program > /dev/null 2>&1

# Use a file as stdin
$ sort < unsorted.txt

Keyboard Shortcuts (Bash)

ShortcutWhat It Does
Ctrl+CKill the current running command (sends SIGINT)
Ctrl+DExit the shell / send EOF
Ctrl+ZSuspend the current process (put it in background)
Ctrl+LClear the screen
Ctrl+AMove cursor to beginning of line
Ctrl+EMove cursor to end of line
Ctrl+WDelete the word before the cursor
Ctrl+UDelete from cursor to beginning of line
Ctrl+RReverse search through command history
Alt+.Insert the last argument of the previous command
Shell Command Lookup Order (Exact):

1. Aliases (defined with alias)
2. Functions (defined with function name() {})
3. Built-in commands (cd, echo, export)
4. External programs (searched in PATH, left to right)

Check which is used: type commandname
Start With Bash

Learn bash first. It's the default everywhere, all tutorials assume it, and scripts are written in it. Once you're comfortable, try zsh or fish for your interactive shell -- but always know bash because that's what servers run.

6. Terminal & ANSI Escape Codes

The terminal emulator (GNOME Terminal, Alacritty, kitty, etc.) is a GUI application that emulates the old hardware terminals from the 1970s. It displays text, accepts keyboard input, and understands special character sequences called ANSI escape codes.

What's a Terminal?

The Old Days (1970s): Today: ┌──────────────────┐ ┌──────────────────┐ │ VT100 Terminal │ physical │ Terminal │ software │ (hardware) │ device │ Emulator (GUI) │ application │ │ │ │ │ CRT screen │ │ ┌─────────────┐ │ │ + keyboard │ │ │ Shell │ │ │ connected via │ │ │ (bash/zsh) │ │ │ serial cable │ │ └─────────────┘ │ │ to mainframe │ │ │ └──────────────────┘ └──────────────────┘

Terminal emulators pretend to be those old hardware terminals. The protocol they use (ANSI escape sequences) is the same one from the 1970s VT100 terminal, just extended over the decades.

ANSI Escape Codes

An ANSI escape code is a special sequence of characters that starts with ESC[ (escape character followed by [). The terminal interprets these sequences as formatting commands instead of printing them as text.

The escape character is \033 (octal), \x1b (hex), or \e (bash shorthand). It's ASCII code 27.

Text Colors

Shell
# Format: \033[CODEm  (the 'm' at the end is required)

# Basic colors (foreground)
echo -e "\033[31mRed text\033[0m"
echo -e "\033[32mGreen text\033[0m"
echo -e "\033[33mYellow text\033[0m"
echo -e "\033[34mBlue text\033[0m"
echo -e "\033[35mMagenta text\033[0m"
echo -e "\033[36mCyan text\033[0m"

# \033[0m resets formatting back to default (always reset!)

# Background colors (add 10 to the foreground code)
echo -e "\033[41mRed background\033[0m"
echo -e "\033[42mGreen background\033[0m"

# Bold, underline, etc.
echo -e "\033[1mBold\033[0m"
echo -e "\033[4mUnderlined\033[0m"
echo -e "\033[1;31mBold Red\033[0m"

# Combine multiple styles with semicolons
echo -e "\033[1;4;33mBold underlined yellow\033[0m"

Color Code Reference

CodeForegroundBackground
30 / 40BlackBlack
31 / 41RedRed
32 / 42GreenGreen
33 / 43YellowYellow
34 / 44BlueBlue
35 / 45MagentaMagenta
36 / 46CyanCyan
37 / 47WhiteWhite
CodeEffect
0Reset all formatting
1Bold / bright
2Dim
4Underline
5Blink (not supported everywhere)
7Reverse (swap foreground/background)

256 Color and True Color

Shell
# 256 color mode: \033[38;5;COLORm (foreground)
echo -e "\033[38;5;208mOrange text (color 208)\033[0m"
echo -e "\033[48;5;21mBlue background (color 21)\033[0m"

# True color (24-bit RGB): \033[38;2;R;G;Bm
echo -e "\033[38;2;255;100;0mRGB orange\033[0m"
echo -e "\033[48;2;0;50;100mRGB dark blue bg\033[0m"

Cursor Movement

Shell
# Move cursor up/down/forward/back
echo -e "\033[2A"     # move up 2 lines
echo -e "\033[3B"     # move down 3 lines
echo -e "\033[5C"     # move forward 5 columns
echo -e "\033[2D"     # move back 2 columns

# Move to specific position (row;column)
echo -e "\033[10;20H" # move to row 10, column 20

# Clear screen
echo -e "\033[2J"     # clear entire screen
echo -e "\033[K"      # clear from cursor to end of line

# Save and restore cursor position
echo -e "\033[s"      # save position
echo -e "\033[u"      # restore position

Why ANSI Codes Matter

ANSI codes are how every colorful CLI tool works:

  • ls --color uses ANSI codes to color directories blue, executables green, etc.
  • git diff uses red/green ANSI codes for removed/added lines
  • Your shell prompt (PS1) uses ANSI codes for colors
  • Progress bars in npm install, pip install use cursor movement codes
  • Text editors like vim and nano use ANSI codes to render the entire UI
Try It: Custom Colored Prompt
Shell
# A colorful bash prompt with username, directory, and git branch
export PS1="\[\033[1;32m\]\u\[\033[0m\]@\[\033[1;34m\]\h\[\033[0m\]:\[\033[1;33m\]\w\[\033[0m\]\$ "

# \u = username, \h = hostname, \w = working directory
# \[...\] tells bash not to count these characters for line wrapping

7. Linux Directory Structure (FHS)

Linux uses a single directory tree starting from / (root). There are no drive letters like C:\ on Windows. Everything -- your files, devices, running processes -- lives somewhere in this tree. The layout follows the Filesystem Hierarchy Standard (FHS).

/ ← Root of everything ├── bin/ ← Essential command binaries (ls, cp, cat, bash) ├── sbin/ ← System binaries (fdisk, iptables, mount) ├── boot/ ← Kernel and bootloader files ├── dev/ ← Device files (every hardware device is a file here) │ ├── sda ← First hard drive │ ├── sda1 ← First partition of first drive │ ├── null ← The void (discards anything written to it) │ ├── zero ← Infinite stream of zero bytes │ ├── random ← Random bytes (for encryption keys etc.) │ └── tty ← Your terminal ├── etc/ ← System configuration files (text files you edit) │ ├── fstab ← Filesystem mount points │ ├── hostname ← Your computer's name │ ├── hosts ← Local DNS overrides │ ├── passwd ← User account info │ ├── shadow ← Password hashes (root only) │ ├── apt/ ← APT package manager config │ │ └── sources.list.d/ ← Package repository URLs │ └── systemd/ ← Service configuration ├── home/ ← User home directories │ └── sean/ ← YOUR stuff lives here │ ├── Desktop/ │ ├── Documents/ │ ├── Downloads/ │ ├── .bashrc ← Your shell configuration │ ├── .config/ ← App configs (XDG standard) │ ├── .local/ ← User-installed programs and data │ └── .ssh/ ← SSH keys ├── lib/ ← Shared libraries (like .dll on Windows) ├── media/ ← Auto-mounted removable drives (USB, CD) ├── mnt/ ← Manually mounted filesystems ├── opt/ ← Optional third-party software ├── proc/ ← Virtual filesystem -- running process info │ ├── cpuinfo ← CPU details │ ├── meminfo ← Memory details │ └── [pid]/ ← Info about each running process ├── root/ ← Root user's home directory (not /home/root) ├── run/ ← Runtime data (PIDs, sockets) -- cleared on reboot ├── srv/ ← Data for services (web server files, etc.) ├── sys/ ← Virtual filesystem -- hardware/driver info ├── tmp/ ← Temporary files (cleared on reboot) ├── usr/ ← User programs and data (read-only) │ ├── bin/ ← Most user commands (git, python, gcc, node) │ ├── lib/ ← Libraries for /usr/bin programs │ ├── local/ ← Locally compiled software │ │ ├── bin/ ← Your manually installed programs │ │ └── lib/ │ ├── share/ ← Architecture-independent data (docs, icons) │ └── include/ ← C/C++ header files └── var/ ← Variable data (changes during operation) ├── log/ ← System logs │ ├── syslog ← General system log │ └── auth.log ← Authentication log ├── cache/ ← Application caches (apt downloads etc.) ├── lib/ ← Variable state data (databases, package info) └── tmp/ ← Persistent temp files (survives reboot)

The Most Important Directories for You

DirectoryWhat You Use It For
~ (home)Your files, projects, configs. cd ~ or just cd goes here.
/etcWhen you need to configure system software (nginx, ssh, network, etc.)
/var/logWhen something breaks -- check the logs here.
/tmpThrow temporary files here. Cleared on reboot.
/usr/binWhere most programs live. which python3 shows you the exact path.
/devDevice files. /dev/null is your best friend for discarding output.
/procProcess and system info. cat /proc/cpuinfo shows CPU details.

Everything Is a File

This is the fundamental Unix philosophy. In Linux, everything is represented as a file:

  • Regular files -- text, images, binaries. The obvious ones.
  • Directories -- special files that contain lists of other files.
  • Device files (/dev/sda) -- reading/writing these talks directly to hardware.
  • Pipes (|) -- connect the output of one program to the input of another.
  • Sockets -- network connections and inter-process communication.
  • Symlinks -- pointers to other files.
  • Process info (/proc/1234/status) -- kernel data exposed as readable files.
Example: Exploring Your System
Shell
# How much disk space is each top-level directory using?
$ sudo du -sh /* 2>/dev/null | sort -hr | head -10

# What's in /dev? (your devices)
$ ls /dev | head -20

# Read your CPU info (it's just a "file")
$ cat /proc/cpuinfo | grep "model name" | head -1

# How long has your system been running?
$ cat /proc/uptime

# What filesystems are mounted?
$ df -h

8. Users & Permissions

Linux is a multi-user system. Every file is owned by a user and a group, and has permission bits that control who can read, write, or execute it.

Users and Groups

Shell
# Who am I?
$ whoami
sean

# What groups am I in?
$ groups
sean adm cdrom sudo dip plugdev lpadmin

# User info (from /etc/passwd)
$ id
uid=1000(sean) gid=1000(sean) groups=1000(sean),27(sudo),...

# The root user (UID 0) can do ANYTHING
# Use sudo to run commands as root
$ sudo apt update

Permission Bits

$ ls -la drwxr-xr-x 2 sean sean 4096 Feb 23 10:30 Documents -rw-r--r-- 1 sean sean 156 Feb 23 10:30 notes.txt -rwxr-xr-x 1 sean sean 892 Feb 23 10:30 script.sh lrwxrwxrwx 1 sean sean 11 Feb 23 10:30 link -> target.txt │├─┤├─┤├─┤ │ │ │ └── Others (everyone else) │ │ └───── Group │ └──────── Owner └────────── Type: d=dir, -=file, l=symlink r = read (4) w = write (2) x = execute (1)

For files: r = read the contents, w = modify it, x = run it as a program.

For directories: r = list contents (ls), w = create/delete files inside, x = enter the directory (cd).

Shell
# Change permissions (numeric)
$ chmod 755 script.sh    # rwxr-xr-x (owner: all, group/others: read+exec)
$ chmod 644 notes.txt    # rw-r--r-- (owner: read+write, group/others: read)
$ chmod 700 private/     # rwx------ (owner only)

# Change permissions (symbolic)
$ chmod +x script.sh     # add execute for everyone
$ chmod u+x script.sh    # add execute for owner only
$ chmod go-w file.txt    # remove write for group and others

# Change ownership
$ sudo chown sean:sean file.txt
$ sudo chown -R sean:sean directory/   # recursive

sudo -- Doing Things as Root

sudo (superuser do) runs a single command as root. Your user must be in the sudo group. On Pop!_OS, your first user is automatically in the sudo group.

Shell
# Install software (needs root)
$ sudo apt install git

# Edit a system config file
$ sudo nano /etc/hosts

# Become root for multiple commands (use sparingly)
$ sudo -i         # opens a root shell
# exit            # go back to your user

# Run the last command with sudo
$ apt update      # oops, permission denied
$ sudo !!         # runs "sudo apt update"
Don't Run Everything as Root

Only use sudo when you actually need elevated privileges (installing software, editing system files, managing services). Running everyday commands as root is dangerous -- a typo like sudo rm -rf / would destroy your entire system. The permission system exists to protect you from yourself.

9. Package Management (apt)

On Linux, you don't download .exe files from websites. Instead, you use a package manager that downloads, installs, updates, and removes software from trusted repositories (servers that host packages).

Pop!_OS uses apt (Advanced Package Tool) because it's Debian/Ubuntu-based. Packages are .deb files.

How apt Works

Your machine Remote repository ──────────── (e.g., archive.ubuntu.com) ┌──────────────────────┐ $ sudo apt update ──────────────→ │ Package lists │ (downloads package lists) │ (what's available) │ └──────────────────────┘ $ sudo apt install git ──────────→ ┌──────────────────────┐ (downloads .deb files) │ .deb package files │ installs them locally │ (actual software) │ └──────────────────────┘ apt handles: - Downloading packages - Resolving dependencies (git needs libcurl, libz, etc.) - Installing files to correct locations - Tracking what's installed - Upgrading and removing packages

Essential apt Commands

Shell
# === ALWAYS UPDATE FIRST ===
$ sudo apt update              # refresh package lists (what's available)
$ sudo apt upgrade             # upgrade all installed packages
$ sudo apt full-upgrade        # upgrade + handle dependency changes

# === INSTALL ===
$ sudo apt install git         # install a package
$ sudo apt install git curl wget  # install multiple at once
$ sudo apt install -y git      # auto-answer yes to prompts

# === REMOVE ===
$ sudo apt remove firefox      # remove package (keeps config files)
$ sudo apt purge firefox       # remove package + config files
$ sudo apt autoremove           # remove unused dependencies

# === SEARCH ===
$ apt search "text editor"     # search for packages
$ apt show git                 # show details about a package
$ apt list --installed         # list all installed packages
$ apt list --installed | grep python  # find installed python packages

# === INFO ===
$ dpkg -L git                  # list all files installed by a package
$ dpkg -S /usr/bin/git         # which package owns this file?
$ apt policy git               # show installed and available versions

Repositories (PPAs)

Sometimes the version in the default repositories is old. You can add extra PPAs (Personal Package Archives) for newer or third-party software:

Shell
# Add a PPA (example: newer version of something)
$ sudo add-apt-repository ppa:some-ppa/name
$ sudo apt update
$ sudo apt install package-name

# Remove a PPA
$ sudo add-apt-repository --remove ppa:some-ppa/name

Other Ways to Install Software on Pop!_OS

MethodCommandWhen to Use
aptsudo apt installDefault. Use this first.
Flatpakflatpak installSandboxed apps. Pop!_Shop uses this. Good for GUI apps.
Snapsnap installCanonical's format. Some apps only available here.
.deb filesudo dpkg -i file.debDownloaded .deb from a website (e.g., VS Code, Discord).
AppImagechmod +x app.AppImage && ./app.AppImagePortable apps. Just download and run.
From source./configure && make && sudo make installLast resort. Compiling from source code.
Keep Your System Updated

Run sudo apt update && sudo apt upgrade regularly (at least weekly). This gets you security patches and bug fixes. Pop!_OS also shows updates in the system tray. Don't ignore them -- they include kernel and security updates.

10. Bash Scripting Basics

A Bash script is a text file containing a series of commands that bash executes one by one. Instead of typing commands manually, you write them in a file and run the file. This lets you automate repetitive tasks.

Bash Safety Header (Mandatory for Scripts):

set -euo pipefail

-e: Exit immediately if any command fails
-u: Treat unset variables as errors
-o pipefail: Pipe fails if ANY command in the pipe fails (not just the last)

Your First Script

Bash
#!/bin/bash
# The first line (shebang) tells the OS to use bash to run this file

# Print a greeting
echo "Hello, $(whoami)!"
echo "Today is $(date +%A)"
echo "You are in: $(pwd)"
Shell
# Save as greeting.sh, make executable, then run
$ chmod +x greeting.sh
$ ./greeting.sh
Hello, sean!
Today is Sunday
You are in: /home/sean

Variables

Bash
#!/bin/bash

# Assign variables (NO spaces around =)
name="Sean"
age=25
directory="/home/sean"

# Use variables with $ prefix
echo "Name: $name"
echo "Age: $age"

# Curly braces for clarity (needed when variable is next to other text)
echo "${name}'s files are in ${directory}"

# Command substitution: capture command output in a variable
current_date=$(date +%Y-%m-%d)
file_count=$(ls | wc -l)
echo "Date: $current_date, Files in current dir: $file_count"

# Read user input
read -p "Enter your name: " user_name
echo "Hello, $user_name!"
No Spaces Around =

name="Sean" works. name = "Sean" does NOT -- bash thinks name is a command. This catches everyone at first.

Conditionals (if/else)

Bash
#!/bin/bash

# Check if a file exists
if [ -f "$HOME/.bashrc" ]; then
    echo ".bashrc exists"
else
    echo ".bashrc not found"
fi

# Check if a directory exists
if [ -d "/tmp" ]; then
    echo "/tmp is a directory"
fi

# String comparison
name="sean"
if [ "$name" = "sean" ]; then
    echo "Hello Sean!"
fi

# Number comparison
count=5
if [ "$count" -gt 3 ]; then
    echo "Count is greater than 3"
elif [ "$count" -eq 3 ]; then
    echo "Count is exactly 3"
else
    echo "Count is less than 3"
fi

# Check if a command exists
if command -v git &>/dev/null; then
    echo "git is installed: $(git --version)"
else
    echo "git is not installed"
fi

Test Operators Reference

OperatorMeaning
-f fileFile exists and is a regular file
-d dirDirectory exists
-e pathPath exists (file or directory)
-r fileFile is readable
-w fileFile is writable
-x fileFile is executable
-z "$var"String is empty
-n "$var"String is not empty
"$a" = "$b"Strings are equal
"$a" != "$b"Strings are not equal
$a -eq $bNumbers are equal
$a -ne $bNumbers are not equal
$a -gt $ba greater than b
$a -lt $ba less than b
$a -ge $ba greater than or equal to b
$a -le $ba less than or equal to b

Loops

Bash
#!/bin/bash

# For loop (iterate over a list)
for fruit in apple banana cherry; do
    echo "I like $fruit"
done

# For loop (iterate over files)
for file in *.txt; do
    echo "Processing: $file"
    wc -l "$file"
done

# For loop (C-style, count from 1 to 5)
for (( i=1; i<=5; i++ )); do
    echo "Count: $i"
done

# While loop
count=0
while [ "$count" -lt 5 ]; do
    echo "Count is $count"
    count=$(( count + 1 ))
done

# Read a file line by line
while IFS= read -r line; do
    echo "Line: $line"
done < input.txt

Functions

Bash
#!/bin/bash

# Define a function
greet() {
    local name="$1"    # $1 is the first argument
    echo "Hello, $name!"
}

# Call it
greet "Sean"
greet "World"

# Function with return value (actually exit code, 0-255)
is_even() {
    if (( $1 % 2 == 0 )); then
        return 0   # success (true)
    else
        return 1   # failure (false)
    fi
}

if is_even 4; then
    echo "4 is even"
fi

# Function that outputs a value (capture with $())
get_extension() {
    echo "${1##*.}"    # parameter expansion: get text after last .
}

ext=$(get_extension "photo.jpg")
echo "Extension: $ext"   # jpg

Script Arguments

Bash
#!/bin/bash
# Save as args.sh

echo "Script name: $0"
echo "First arg:   $1"
echo "Second arg:  $2"
echo "All args:    $@"
echo "Num of args: $#"
echo "Exit code of last command: $?"

# Usage: ./args.sh hello world
# Script name: ./args.sh
# First arg:   hello
# Second arg:  world
# All args:    hello world
# Num of args: 2
Practical Script: Backup Your Projects
Bash
#!/bin/bash
# backup.sh -- backup a directory to a timestamped tar.gz

if [ -z "$1" ]; then
    echo "Usage: $0 <directory>"
    exit 1
fi

if [ ! -d "$1" ]; then
    echo "Error: '$1' is not a directory"
    exit 1
fi

timestamp=$(date +%Y%m%d_%H%M%S)
dirname=$(basename "$1")
backup_file="${dirname}_backup_${timestamp}.tar.gz"

tar -czf "$backup_file" "$1"
echo "Backup created: $backup_file ($(du -h "$backup_file" | cut -f1))"

11. .bashrc & Shell Configuration

When you open a terminal, bash reads configuration files to set up your environment. The most important one is ~/.bashrc -- this is where you customise your shell experience.

Which Files Are Read and When

FileWhen It's ReadWhat It's For
~/.bashrcEvery new interactive non-login shell (opening a terminal)Aliases, functions, prompt, shell options. This is the main one.
~/.bash_profileLogin shells only (SSH, tty login, first terminal on some systems)Environment variables (PATH, etc.). Usually sources .bashrc.
~/.profileLogin shells (if no .bash_profile exists)Same as .bash_profile. Used by Pop!_OS by default.
/etc/bash.bashrcEvery interactive bash shellSystem-wide defaults. Don't edit this -- use your ~/.bashrc.
/etc/profileAll login shellsSystem-wide login setup.
When you open a terminal on Pop!_OS: 1. /etc/profile (system-wide login setup) 2. ~/.profile (your login setup -- sets PATH etc.) └── sources ~/.bashrc (your interactive shell setup) 3. ~/.bashrc (aliases, prompt, functions) When you SSH into a machine: Same order, but it's a "login shell" so .bash_profile/.profile are guaranteed to run.

What to Put in .bashrc

Bash
# === ALIASES ===
# Shortcuts for commands you type frequently

alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

# Safety aliases (ask before overwriting)
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'

# Git shortcuts
alias gs='git status'
alias ga='git add'
alias gc='git commit'
alias gp='git push'
alias gl='git log --oneline --graph -10'
alias gd='git diff'

# Navigation shortcuts
alias ..='cd ..'
alias ...='cd ../..'
alias dev='cd ~/Documents/dev'

# System shortcuts
alias update='sudo apt update && sudo apt upgrade'
alias ports='ss -tulnp'
alias myip='curl -s ifconfig.me'

# === FUNCTIONS ===
# More powerful than aliases

# Create a directory and cd into it
mkcd() {
    mkdir -p "$1" && cd "$1"
}

# Extract any archive
extract() {
    case "$1" in
        *.tar.gz|*.tgz)  tar -xzf "$1" ;;
        *.tar.bz2)       tar -xjf "$1" ;;
        *.tar.xz)        tar -xJf "$1" ;;
        *.zip)           unzip "$1" ;;
        *.gz)            gunzip "$1" ;;
        *.7z)            7z x "$1" ;;
        *)               echo "Unknown format: $1" ;;
    esac
}

# === SHELL OPTIONS ===
shopt -s histappend        # append to history, don't overwrite
shopt -s cdspell           # autocorrect small typos in cd
shopt -s autocd            # type a directory name to cd into it

# === HISTORY ===
HISTSIZE=10000             # remember 10000 commands
HISTFILESIZE=20000         # store 20000 in history file
HISTCONTROL=ignoredups:erasedups  # no duplicate entries

# === CUSTOM PROMPT ===
# Green user, blue directory, $ sign
PS1='\[\033[1;32m\]\u\[\033[0m\]:\[\033[1;34m\]\w\[\033[0m\]\$ '

Applying Changes

Shell
# After editing .bashrc, apply changes without restarting terminal
$ source ~/.bashrc
# or
$ . ~/.bashrc

# Open .bashrc to edit
$ nano ~/.bashrc
# or
$ code ~/.bashrc    # if you have VS Code
Start Simple

Don't copy a huge .bashrc from the internet. Start with a few aliases you'll actually use. Add more as you find yourself typing the same things repeatedly. Your .bashrc should be yours -- customised to your workflow.

12. Essential Commands Cheat Sheet

These are the commands you'll use daily. Master them and you'll never feel lost in a terminal again.

Navigation & Files

Shell
# Where am I?
$ pwd                        # print working directory

# Move around
$ cd /path/to/dir            # go to directory
$ cd ~                       # go home (or just: cd)
$ cd ..                      # go up one level
$ cd -                       # go to previous directory

# List files
$ ls                         # basic listing
$ ls -la                     # detailed + hidden files
$ ls -lh                     # human-readable file sizes
$ ls -lt                     # sorted by modification time

# Create
$ touch file.txt             # create empty file (or update timestamp)
$ mkdir mydir                # create directory
$ mkdir -p a/b/c             # create nested directories

# Copy
$ cp source.txt dest.txt     # copy file
$ cp -r source_dir/ dest/    # copy directory recursively

# Move / Rename
$ mv old.txt new.txt         # rename
$ mv file.txt ~/Documents/   # move

# Delete
$ rm file.txt                # delete file
$ rm -r directory/           # delete directory and contents
$ rm -i file.txt             # ask for confirmation first

Reading & Searching Files

Shell
# Read entire file
$ cat file.txt               # print to screen
$ less file.txt              # scrollable viewer (q to quit)

# Read parts of a file
$ head -20 file.txt          # first 20 lines
$ tail -20 file.txt          # last 20 lines
$ tail -f logfile.txt        # follow (live updates -- great for logs)

# Search inside files
$ grep "pattern" file.txt    # find lines matching pattern
$ grep -r "TODO" .           # search recursively in all files
$ grep -i "error" log.txt    # case-insensitive search
$ grep -n "function" *.js    # show line numbers
$ grep -c "error" log.txt    # count matches

# Find files by name
$ find . -name "*.py"        # find all .py files
$ find / -name "nginx.conf"  # find a config file
$ find . -type d -name node_modules  # find directories
$ find . -size +100M         # files larger than 100MB

# Count lines/words/characters
$ wc -l file.txt             # count lines
$ wc -w file.txt             # count words

Disk & System Info

Shell
# Disk usage
$ df -h                      # filesystem usage
$ du -sh ~/Documents         # directory size
$ du -sh */ | sort -hr       # biggest directories first

# System info
$ uname -a                   # kernel and system info
$ lsb_release -a             # distro info
$ free -h                    # memory usage
$ uptime                     # how long the system has been running
$ nproc                      # number of CPU cores

# Who and what
$ whoami                     # current user
$ hostname                   # machine name
$ which python3              # full path of a command
$ type ls                    # is it an alias, function, or binary?

Text Processing

Shell
# Sort lines
$ sort file.txt              # alphabetical sort
$ sort -n file.txt           # numeric sort
$ sort -r file.txt           # reverse sort

# Remove duplicates (input must be sorted)
$ sort file.txt | uniq       # unique lines
$ sort file.txt | uniq -c    # count occurrences

# Cut columns from data
$ cut -d',' -f1,3 data.csv   # extract columns 1 and 3 from CSV
$ cut -d':' -f1 /etc/passwd  # list all usernames

# Stream editor (search and replace)
$ sed 's/old/new/g' file.txt         # replace all occurrences
$ sed -i 's/old/new/g' file.txt      # edit file in-place

# Awk (powerful text processing)
$ awk '{print $1}' file.txt          # print first column
$ awk -F',' '{print $2}' data.csv    # print second column of CSV

Networking

Shell
# Download files
$ wget https://example.com/file.tar.gz
$ curl -O https://example.com/file.tar.gz

# Make HTTP requests
$ curl https://api.example.com/data
$ curl -X POST -d '{"key":"value"}' https://api.example.com

# Network info
$ ip addr                    # show IP addresses
$ ping google.com            # test connectivity
$ ss -tulnp                  # show open ports
$ dig example.com            # DNS lookup
Use man Pages

Every command has a manual page. Type man ls to read the full documentation for ls. Press q to quit. Use /pattern to search within the man page. If man pages are too dense, try tldr ls (install with sudo apt install tldr) for simplified examples.

13. Environment Variables & PATH

Environment variables are key-value pairs that every process inherits from its parent. They configure how programs behave without editing config files.

Shell
# See all environment variables
$ env

# See a specific one
$ echo $HOME          # /home/sean
$ echo $USER          # sean
$ echo $SHELL         # /bin/bash
$ echo $TERM          # xterm-256color
$ echo $EDITOR        # (your default text editor)
$ echo $LANG          # en_US.UTF-8

# Set a variable (current session only)
$ export MY_VAR="hello"
$ echo $MY_VAR        # hello

# Set permanently (add to ~/.bashrc)
export EDITOR="nano"
export MY_API_KEY="abc123"

PATH -- The Most Important Variable

PATH is a colon-separated list of directories where the shell looks for executables. When you type git, the shell searches each directory in PATH left-to-right until it finds a git binary.

Shell
# See your PATH
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin

# See it one directory per line
$ echo $PATH | tr ':' '\n'
/usr/local/bin
/usr/bin
/bin
/usr/local/sbin
/usr/sbin

# Where is a command located?
$ which python3        # /usr/bin/python3
$ which git            # /usr/bin/git

# Add a directory to PATH (in ~/.bashrc)
export PATH="$HOME/.local/bin:$PATH"

# This prepends your local bin directory, so programs
# installed there are found before system ones
You type: git status Shell searches PATH directories in order: /usr/local/bin/git → not found /usr/bin/git → FOUND! Execute this one. If git isn't in any PATH directory: bash: git: command not found

Common PATH Additions

Bash
# Add these to ~/.bashrc if you need them

# Your personal scripts
export PATH="$HOME/.local/bin:$PATH"

# Node.js (nvm)
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

# Go
export PATH="$PATH:/usr/local/go/bin"
export PATH="$PATH:$HOME/go/bin"

# Rust (cargo)
export PATH="$HOME/.cargo/bin:$PATH"

# Python (pip --user installs)
export PATH="$HOME/.local/bin:$PATH"
command not found?

If you install something and get "command not found", it means the binary isn't in your PATH. Find where it was installed (find / -name "binary_name" 2>/dev/null) and add that directory to your PATH in ~/.bashrc.

14. Processes & Services

Every running program is a process. The OS page covers processes in depth -- here we focus on practical commands for managing them on your Pop!_OS system.

Viewing Processes

Shell
# See all running processes
$ ps aux                     # classic Unix format
$ ps aux | grep firefox      # find a specific process

# Interactive process viewer (much better than ps)
$ htop                       # install: sudo apt install htop

# Process tree (shows parent-child relationships)
$ pstree -p

# What's using the most CPU?
$ ps aux --sort=-%cpu | head -10

# What's using the most memory?
$ ps aux --sort=-%mem | head -10

Managing Processes

Shell
# Run a command in the background
$ ./long_task &              # & puts it in the background
$ jobs                       # list background jobs
$ fg %1                      # bring job 1 to foreground

# Ctrl+Z to suspend a running process, then:
$ bg                         # resume it in the background

# Kill processes
$ kill 1234                  # send SIGTERM (polite: "please stop")
$ kill -9 1234               # send SIGKILL (force kill -- can't be ignored)
$ killall firefox            # kill all processes named firefox
$ pkill -f "python server"   # kill processes matching a pattern

systemd -- Managing Services

Pop!_OS uses systemd to manage services (background programs that start automatically). Web servers, databases, SSH, bluetooth -- all managed by systemd.

Shell
# Check status of a service
$ systemctl status nginx
$ systemctl status ssh
$ systemctl status bluetooth

# Start / stop / restart a service
$ sudo systemctl start nginx
$ sudo systemctl stop nginx
$ sudo systemctl restart nginx

# Enable (start on boot) / disable
$ sudo systemctl enable nginx      # start automatically on boot
$ sudo systemctl disable nginx     # don't start on boot

# List all running services
$ systemctl list-units --type=service --state=running

# See service logs (journalctl)
$ journalctl -u nginx              # logs for nginx
$ journalctl -u nginx --since today
$ journalctl -f                    # follow all logs in real-time
systemctl vs service

You might see older tutorials use sudo service nginx restart. That still works (it's a compatibility wrapper), but systemctl is the modern way and gives you more control.

15. Practice Quiz

Q1: What is the Linux kernel?

The kernel is the core piece of software that runs in privileged mode and manages hardware (CPU, RAM, devices), processes, memory, and file systems. It's just one component of a full operating system -- you need a shell, utilities, and applications on top of it.

Q2: What is the main difference between Unix and Linux?

Unix (1969) is proprietary and commercial. Linux (1991) is a free, open-source reimplementation of Unix ideas. Linux doesn't share code with Unix -- Linus Torvalds wrote it from scratch. Both follow similar conventions (POSIX), which is why commands work on both.

Q3: Which package manager does Pop!_OS use?

Pop!_OS is based on Ubuntu, which is based on Debian. The entire Debian family uses apt/dpkg for package management with .deb packages. pacman is for Arch, dnf is for Fedora/RHEL, and zypper is for openSUSE.

Q4: What is the difference between a terminal and a shell?

The terminal emulator (GNOME Terminal, Alacritty, etc.) is the GUI window that displays text and accepts keyboard input. The shell (bash, zsh, fish) is the program running inside the terminal that interprets your commands and talks to the kernel.

Q5: What does the PATH environment variable do?

PATH is a colon-separated list of directories. When you type a command like "git", the shell searches each directory in PATH from left to right until it finds a matching executable. If it's not in any PATH directory, you get "command not found".

Q6: Where do user home directories live on Linux?

/home contains all regular user home directories (e.g., /home/sean). The root user is special -- its home directory is /root (not /home/root). /usr is for system programs, not user data.

Q7: What does "chmod 755 script.sh" do?

In octal notation: 7=rwx (4+2+1), 5=r-x (4+0+1). So 755 means the owner gets read+write+execute, while group and others get read+execute. This is the standard permission for scripts and programs that everyone should be able to run.

Q8: What happens when you type "sudo apt update"?

"apt update" only refreshes the local list of available packages from the remote repositories. It does NOT install or upgrade anything. You need "apt upgrade" to actually install the updates. Always run "apt update" before "apt upgrade" to make sure you're getting the latest versions.

Q9: What is the shebang line (#!/bin/bash) at the top of a script?

The shebang (#!) on the first line tells the operating system which program to use as the interpreter. #!/bin/bash means "run this file using bash". #!/usr/bin/python3 would mean "run this using Python 3". Without it, the OS doesn't know how to execute the script.

Q10: What does /dev/null do?

/dev/null is a special device file that discards everything written to it and returns nothing when read. It's used to silence output: "command > /dev/null 2>&1" runs a command but throws away all output and errors. /dev/zero is the one that generates null bytes.