Table of Contents
- Module 1: Understanding the Linux Ecosystem
- Module 2: Getting Hands-on with Linux
- Module 3: Working with Files and Directories
- Summary
Module 1: Understanding the Linux Ecosystem
The Linux Kernel and Its Origins
The Linux kernel is what Linux itself really is: everything else built on top of it (desktop environments, package managers, applications) is technically a separate layer. The first version of the kernel was written by Linus Torvalds in 1991 as an effort to replicate the functionality of the commercial Unix operating system using free software. Kernel version numbering has advanced steadily since then (modern systems commonly run kernel version 6.x).
The kernel’s job is to act as the interface between a computer’s physical hardware — RAM, physical storage, and CPU processing power — and the software applications that want to use those resources. Application code (for example, the logic behind a spreadsheet program) would be useless without a mechanism to request and receive access to compute resources; the kernel is that mechanism.
flowchart LR
subgraph HW["Physical Hardware"]
RAM[RAM Memory]
CPU[CPU Processing Power]
DISK[Physical Storage]
end
subgraph KERNEL["Linux Kernel"]
MOD1[Hardware Modules]
SCHED[Resource Scheduler]
end
subgraph APPS["Applications"]
A1[Spreadsheet Program]
A2[Web Browser]
A3[Custom Software]
end
HW <--> KERNEL
KERNEL <--> APPS
The Linux kernel has a modular design: individual software modules can be attached to the kernel to describe hardware devices and how the kernel should interact with them. For example, building a kernel for a smartphone would involve writing or importing modules describing the touch-sensitive glass, cameras, and sensors, plus applications for phone calls, text messaging, and photography. This is precisely what the Android operating system does — the software driving the overwhelming majority of smartphones on Earth is the Linux kernel. Beyond phones, Linux powers the majority of internet servers, network routing devices, supercomputers, and many embedded devices such as thermostats.
The modern Linux kernel consists of roughly 40 million lines of code, counting source code, comments, and documentation. A large portion of that code exists to support the many CPU architectures Linux runs on, including x86, ARM, and RISC-V. Because the kernel is modular, no single installed system uses anywhere near all 40 million lines — only the modules relevant to that machine’s hardware are loaded.
Kernel contribution statistics illustrate how the project is maintained:
| Contributor Category | Approximate Share of Kernel Contributions |
|---|---|
| Private / anonymous individual developers | ~15% (largest single group) |
| Intel | ~10% |
| Red Hat | ~10% |
| ~10% | |
| AMD, IBM, Meta, NVIDIA, Microsoft, and others | Remaining contributions |
More than 80% of the kernel is authored by developers whose time is funded by technology companies that benefit from Linux. Linus Torvalds and his senior maintainer team actively manage contributions to ensure nothing is broken in the process, but the kernel is best understood as a global community project in which some of the most profitable companies in the world actively participate.
A kernel alone is not useful without an application layer installed on top of it. That combined package — kernel plus applications, utilities, and configuration — is called a distribution (or “distro”). Ubuntu, Debian, Fedora, and Red Hat Enterprise Linux are among the most popular distributions. In practice, installing Linux means downloading a complete distribution package from a distro’s website.
Linux Desktop and Shell Environments
There are many ways to get access to a running Linux environment, including:
- Installing from a USB drive onto physical hardware
- Creating a virtual machine (for example, using VirtualBox) running Linux as a desktop or server
- Launching a virtual Linux instance in a cloud platform such as AWS
- Running Linux inside Windows using the Windows Subsystem for Linux (WSL)
- Using someone else’s Linux machine directly
Exploring a graphical desktop. Red Hat Enterprise Linux uses the GNOME desktop manager, which is also used across many other distros, making it a reasonable reference point for understanding a typical Linux desktop layout:
- A dock (a toolbar, often placed along the bottom of the screen by default but repositionable) provides quick access to frequently used applications.
- Multiple virtual desktops can run different sets of applications simultaneously; you switch between them by clicking.
- The software center application is where users find, download, and install packages and extensions from curated software repositories. These repositories handle the full package lifecycle automatically — installation, updates, and security scanning — and typically contain many thousands of free packages.
- The Files application provides basic file management; a check mark in the software center indicates an app is already installed.
- The terminal application is where most Linux system administration work is done, since most admins interact with Linux through the command line rather than a graphical session, and most servers do not even have a graphical desktop installed. A simple first command to try is:
pwd
pwd prints the current working directory. Typing exit closes the terminal.
- A basic text editor app is useful for managing plaintext files such as programming code, without the extra formatting features of a full word processor.
- A calculator application, often with multiple modes including financial calculations.
- An application menu icon exposes all installed apps (including ones not pinned to the dock), and supports text search once many applications are installed.
- System settings, accessible from a gear icon, expose configuration for networking (including multi-display setups), file/media type associations with default applications, online account authentication, keyboard preferences, and automatically detected devices such as network printers.
- A power icon provides a dialog for choosing the machine’s power state (e.g., power off, restart).
Remote access via SSH. Most admins connect to Linux servers directly through a command line rather than logging into a graphical session, most commonly using the Secure Shell (SSH) protocol:
ssh admin1@192.168.101.71
This establishes a remote session on the target Linux server (identified here by its IP address), authenticating as the admin1 account (which will require a password). SSH clients are available on Linux, macOS, and Windows, so as long as you have valid credentials and network connectivity you can administer Linux servers from virtually anywhere. Once connected via SSH, you land at the same file-system location and shell environment you would reach by opening a terminal window locally inside a graphical desktop session.
flowchart TD
U[Administrator] -->|Local terminal in GNOME desktop| T[Bash Shell Session]
U -->|"ssh admin1@192.168.101.71"| S[SSH Remote Session]
S --> T
T --> FS[Same Linux File System / Same Working Directory]
How Applications Interact with the Linux Kernel
Beyond the kernel itself, several other layers are involved before a user ever reaches a working desktop or shell:
- GRUB (GRand Unified Bootloader) — takes over from the Master Boot Record (MBR), which lives in the first sector of a boot device and is itself loaded by the machine’s BIOS or UEFI firmware. GRUB can present a menu listing each operating system kernel available to boot, but typically it automatically and invisibly loads the latest available kernel; the menu is normally only seen if something has gone wrong during startup.
- The Linux kernel loads into memory.
- The init manager begins launching system services, background programs, and logging processes — including database servers and application software (for example, on a machine serving a public-facing website) — as well as executing any scheduled automated tasks that the system or its users have configured. On most modern Linux distributions, the init manager is systemd, which comes with its own family of administration tools for customizing and maintaining running systems.
flowchart LR
BIOS["BIOS / UEFI Firmware"] --> MBR["Master Boot Record"]
MBR --> GRUB["GRUB Bootloader"]
GRUB -->|Loads latest kernel automatically, or shows boot menu on failure| KERNEL["Linux Kernel Loaded into Memory"]
KERNEL --> INIT["Init Manager (systemd)"]
INIT --> SVC["System Services, Applications, Scheduled Tasks"]
Linux configuration settings are almost always stored in plaintext files somewhere in the file system — in fact, nearly all Linux data of any kind lives in plaintext files within the file system hierarchy. Understanding how to locate important resources and make changes to the system therefore depends on understanding how that file system is organized (covered later in this module).
Example: how a real application is assembled from many file-system locations. Using the Wireshark network packet analyzer as an illustration (the specific application is not important — the point is how many different parts must exist and cooperate to make any Linux application function):
| Purpose | Location |
|---|---|
| Compiled program binary | /usr/bin/wireshark |
| Per-user recent settings (auto-generated) | User’s personal file hierarchy |
| Shared libraries and plugins | /usr/lib/x86_64-linux-gnu/ |
| Static data, configuration, dictionaries, documentation | /usr/share/wireshark/ |
| HTML documentation manuals | /usr/share/doc/wireshark/ |
| Package lifecycle metadata (install/upgrade/removal records) | dpkg info files referencing Wireshark |
| Application icons and other trivial assets | Dedicated image files elsewhere in /usr/share |
All of this documentation is also reachable through the traditional man system (covered later). The overall picture: from the systemd init manager down to the many scattered files an individual application needs, a large number of layers must work together so that, by the time you log into a graphical desktop or a terminal shell, you have an active, fully functioning system ready to use.
Choosing a Linux Distribution
Every Linux distribution is built around the same official Linux kernel, but each one adds its own set of packages and configuration profiles. Beyond well-known general-purpose distros like Ubuntu and Red Hat, there are hundreds of smaller distros built for specialized use cases.
Ranking distros purely by installation count is not very meaningful, because Linux serves very different purposes across different contexts:
- Amazon Linux 2 is technically among the top few distros by install count, but primarily because it was built by Amazon specifically for AWS and is heavily used there — not because many people install it on laptops or in local datacenters.
- Kali Linux does not have anywhere near the raw install numbers of general-purpose distros, but it dominates its niche: cybersecurity and penetration testing. Kali is built on top of Ubuntu, which is itself built on top of Debian — Ubuntu is essentially a customized Debian, and Kali is a customized Ubuntu, each release rebuilt from its respective parent.
flowchart TD
DEBIAN["Debian (stability-focused, APT package manager)"]
UBUNTU["Ubuntu (general-purpose, maintained by Canonical)"]
KALI["Kali Linux (penetration testing / security)"]
MINT["Linux Mint (desktop-friendly)"]
ZORIN["Zorin OS (Windows-migration friendly)"]
ELEM["Elementary OS (macOS-like interface)"]
XUBUNTU["Xubuntu (lightweight, older hardware)"]
RHEL["Red Hat Enterprise Linux (commercial license model)"]
FEDORA["Fedora (free upstream testbed)"]
CENTOSSTREAM["CentOS Stream (free upstream testbed)"]
ALMA["AlmaLinux (RHEL-compatible)"]
ROCKY["Rocky Linux (RHEL-compatible)"]
ARCH["Arch Linux (independent, minimal, highly customizable)"]
OPENSUSE["openSUSE (independent, enterprise workloads)"]
DEBIAN --> UBUNTU
UBUNTU --> KALI
UBUNTU --> MINT
UBUNTU --> ZORIN
UBUNTU --> ELEM
UBUNTU --> XUBUNTU
RHEL --> FEDORA
RHEL --> CENTOSSTREAM
RHEL -.compatible clone.-> ALMA
RHEL -.compatible clone.-> ROCKY
Debian family. Debian’s primary value proposition is stability: updates are infrequent, but reliable, making it attractive for enterprise server workloads. Debian is also the origin of the APT package manager, the front end for Debian’s software repositories. Any distro built on Debian inherits seamless integration with the thousands of open-source packages managed by APT.
- Ubuntu — a Debian derivative prepared for use anywhere: servers, hypervisors, public/private cloud platforms, routers, desktops, and laptops. Ubuntu is free, though Canonical (its corporate maintainer) sells enterprise-level support plans for large or complex deployments. Every 2 years Ubuntu ships a Long-Term Support (LTS) release, with support lasting up to 10 years — well suited to deployments meant to run for years without reinstallation.
- Ubuntu itself is a parent to further distros: Linux Mint (popular desktop interface), Zorin OS (aimed at users migrating from Windows), Elementary OS (closer in feel to macOS), and Xubuntu (runs well even on older, lower-powered machines).
Red Hat family. Red Hat Enterprise Linux (RHEL) is built around a commercial licensing model where business users purchase per-machine licenses. Red Hat also supports the free Fedora and CentOS Stream distros, which serve as testbeds for features that eventually make their way into RHEL. CentOS historically mirrored RHEL exactly and was fully open, but Red Hat discontinued that model. Independent projects AlmaLinux and Rocky Linux now provide feature-for-feature compatibility with the latest RHEL releases.
Independent distros.
- Arch Linux — minimal, highly customizable, and by reputation best suited to serious and experienced administrators; those who adopt it tend to prefer it strongly over alternatives.
- openSUSE — popular with experienced administrators for enterprise workloads, offering multiple distro variants for a range of applications.
| Distro | Base | Primary Use Case / Niche |
|---|---|---|
| Debian | — (Foundational) | Long-term server stability |
| Ubuntu | Debian | General-purpose (desktop, server, cloud) |
| Kali Linux | Ubuntu → Debian | Cybersecurity / penetration testing |
| Linux Mint | Ubuntu | Desktop-focused interface |
| Zorin OS | Ubuntu | Windows-to-Linux migration |
| Elementary OS | Ubuntu | macOS-like desktop experience |
| Xubuntu | Ubuntu | Lightweight, older hardware |
| Amazon Linux 2 | Independent | Optimized for AWS Cloud |
| Red Hat Enterprise Linux | — (Foundational) | Commercial enterprise support |
| Fedora | RHEL upstream | Free testbed for new RHEL features |
| CentOS Stream | RHEL upstream | Free testbed for new RHEL features |
| AlmaLinux | RHEL-compatible clone | Free, fully RHEL-compatible |
| Rocky Linux | RHEL-compatible clone | Free, fully RHEL-compatible |
| Arch Linux | Independent | Minimal, highly customizable |
| openSUSE | Independent | Enterprise workloads |
Using Open Source Software Responsibly
“Open source” means that the software, labor, or assets that went into an item have been donated to the world, generally with some conditions attached. It is the responsibility of anyone installing and using open-source software to understand which conditions apply and to respect them. In most cases restrictions are minor and will rarely limit ordinary use, but understanding license categories is still important.
flowchart TD
OSS["Open Source Licenses"]
OSS --> PERM["Permissive Licenses"]
OSS --> COPY["Copyleft / Reciprocal Licenses"]
OSS --> PUB["Public Domain"]
PERM --> MIT["MIT License"]
PERM --> APACHE["Apache 2.0 License"]
COPY --> STRONG["Strong Copyleft"]
COPY --> WEAK["Weak Copyleft"]
STRONG --> GPL2["GNU GPL v2"]
STRONG --> GPL3["GNU GPL v3"]
WEAK --> MPL["Mozilla Public License"]
Permissive licenses (MIT, Apache) come with minimal conditions: they permit commercial use and inclusion in closed-source projects. Typically only the original license text and attribution need to be included in redistributions.
- The Apache 2.0 license includes a patent retaliation clause: usage rights terminate if you or your organization launch a patent lawsuit against anyone involved with the open-source project. The Android Open Source Project and Kubernetes use the Apache license.
- The MIT license is used by well-known tools such as Node.js and Ruby on Rails.
Copyleft (reciprocal) licenses come in two flavors:
- Strong copyleft requires any derivative work to be licensed under a compatible license. The GNU GPL versions 2 and 3 are strong copyleft examples; the Linux kernel itself uses GPL v2, and the R programming language is protected by GPL v3.
- Weak copyleft protects only the core library itself while allowing inclusion in larger proprietary systems, as long as the core remains open. The Mozilla Public License (MPL), used by LibreOffice, is a weak copyleft example — it allows derivative works to include dynamic links to proprietary applications (for example, enabling third-party stock-price API integrations inside a LibreOffice Calc spreadsheet).
Public domain licenses effectively assign full ownership rights to whoever uses the software. Typical limits are only that the software must not be used in the commission of a crime and that its use must not create legal liability for the original creators.
Creative Commons licenses also exist, with many possible clause combinations, but they are typically used for content rather than software.
| License Category | Examples | Key Characteristic |
|---|---|---|
| Permissive | MIT, Apache 2.0 | Minimal conditions; usable in closed-source/commercial projects |
| Strong Copyleft | GNU GPL v2, GNU GPL v3 | Derivative works must use a compatible open license |
| Weak Copyleft | Mozilla Public License (MPL) | Core library stays open; can link into proprietary systems |
| Public Domain | — | Full ownership assigned to the user, minimal restrictions |
| Creative Commons | Various clause combinations | Typically used for content, not software |
The open-source movement, with Linux as its most visible achievement, has given countless people tools to earn a living and build valuable projects. Some projects (like the Linux kernel) are backed by powerful corporations, while others are quietly maintained by one or two volunteers — including projects that play critical roles in the infrastructure underpinning the internet and modern society. Historically, the people maintaining those projects have donated their time to make things better, though there have been cases where the influence of core projects has been misused for criminal or political ends. For that reason, it is worth doing some research into licensing and provenance whenever adding third-party components to your own projects.
Module 2: Getting Hands-on with Linux
Installing a Linux Environment
There is no single way to get Linux installed, and the number of possible target hosts and installation types is very large. A few common, representative approaches:
Windows Subsystem for Linux (WSL). For Windows users, WSL provides a CLI-based platform for running virtualized Linux environments directly inside the Windows Command Prompt — without a graphical Linux desktop, but with a full Ubuntu, Debian, or other distro experience.
wsl --install Debian
The first run can take a minute or more to complete. On first launch you are prompted to create a new account (any username you choose). The Windows prompt visibly changes to indicate you are now inside the Linux subsystem. You can confirm the kernel is genuinely Linux with:
uname -a
This typically reports a specialized Microsoft-built kernel that is nonetheless a real Linux kernel — WSL was built as a collaboration between Microsoft and Canonical engineers.
Creating a bootable USB stick. This is the most common approach for installing Linux onto physical hardware, whether a server or a personal laptop. General process (following the official Ubuntu installation guide, though the steps are broadly similar for any distro):
- Confirm the target machine meets the minimum hardware requirements for the distro (or simply try the live desktop without installing, to check for compatibility problems).
- Back up or confirm you have no important data on the target drive and on the USB stick being used to create the installer — both will be irreversibly overwritten.
- Download the appropriate installer image (typically the most recent AMD64 image) from the official distro website.
- Use a tool appropriate to your current operating system to write the image to the USB stick — for example, Rufus on Windows, or balenaEtcher on macOS/Linux.
- Shut down the target machine, plug in the USB stick, and power on. With most modern firmware the system boots directly into the installer; otherwise, boot-order/BIOS settings may need to be adjusted to force the machine to boot from USB.
- Proceed through the distro’s installation wizard.
Launching a Linux instance in AWS. With an active AWS account and the AWS CLI installed, a live Linux server instance can be created with a single command:
aws ec2 run-instances \
--image-id ami-xxxxxxxxxxxxxxxxx \
--count 1 \
--instance-type t2.micro \
--key-name MyKeyPair \
--security-group-ids sg-xxxxxxxx \
--subnet-id subnet-xxxxxxxx
This creates a headless AWS instance running Amazon Linux 2 (no desktop — just a server you would reach over SSH). Prerequisites for this command to work:
- A valid, current AMI (
--image-id) available in your default AWS region. - A previously created key pair (here,
MyKeyPair) in the correct region, so you can SSH into the instance once it launches. - Valid, existing security group and subnet IDs.
This can equally be done through the AWS web console, but the CLI offers simplicity and fine-grained control once the required values are known.
Installing a Linux Virtual Machine Using VirtualBox
Running Linux inside a virtual machine is a practical option when dedicated hardware is not available. Oracle VirtualBox is a reliable, relatively simple, cross-platform choice for this. VMs allow different Linux versions (e.g., an older Ubuntu release alongside a newer Red Hat Enterprise Linux release) to run side-by-side on the same host.
Creating a new VM — step by step:
- Click the New icon in VirtualBox to define a new VM, and give it a name.
- Point VirtualBox to an Ubuntu ISO image; if VirtualBox already knows about a downloaded ISO, it will be offered automatically, and the OS type/version fields populate accordingly.
- On the Unattended Install tab, credentials for a new system user and a custom hostname can be preset — though for a manual Ubuntu install, the actual installation process will override these preset values (the initial password shown here should still be strengthened later).
- Adjust memory and CPU allocation using the sliders if the workload needs more than the defaults — but avoid over-allocating, since excessive VM resource usage can degrade the host machine’s own performance.
- Adjust storage size similarly — roughly 25 GB is sufficient for a functional Ubuntu desktop install, more if heavy local data writes are expected. Storage and other limits can be edited later and take effect on the VM’s next boot.
- Click Finish, then start the VM.
Running the Ubuntu installer inside the VM:
- If the installer display is too large for the VirtualBox window, switch the VM display to Scale mode (the right Ctrl key + C combination reverses a broken auto-scale change, if needed).
- Select the desired language, any needed accessibility accommodations, and keyboard layout (all changeable later).
- Select an internet connection — a VM will typically share the host workstation’s own network connection.
- Optionally update the installer itself if prompted (recommended, though it can be skipped for a quick pass).
- Choose Try Ubuntu to only test the OS, or Install Ubuntu to proceed directly to installation.
- Choose the interactive install process (unless you have a prepared auto-install template).
- Enable both updates during install and third-party software options for full system functionality (recommended unless you specifically want to avoid non-free components).
- Choose a disk option:
- Erase disk — the simplest option; wipes the (virtual) disk clean for a fresh install. On a VM, this only affects the VM’s virtual disk, not the host machine’s physical drive. On real hardware, this would wipe the physical drive.
- Manual installation — allows dual-boot alongside an existing OS (e.g., Windows) or custom partition/mount-point assignment.
- Set a computer name, username, and password (a common convention for VMs/containers is a simple username like
ubuntu). - Confirm the detected time zone.
- Review all settings, then click Install. Installation can take up to around 30 minutes.
Booting into the new VM: select the VM in VirtualBox and click the green Start icon; the boot process may take a little longer than usual because of the added virtualization layers. Log in with the password created during installation.
flowchart TD
A["Create New VM in VirtualBox"] --> B["Attach Ubuntu ISO Image"]
B --> C["Configure CPU / RAM / Storage Allocation"]
C --> D["Start VM -> Boot Installer"]
D --> E["Choose Language, Accessibility, Keyboard"]
E --> F["Connect to Network"]
F --> G{"Try Ubuntu or Install Ubuntu?"}
G -->|Try| H["Live Desktop (no install)"]
G -->|Install| I["Choose Interactive or Automated Install"]
I --> J["Enable Updates + Third-Party Software"]
J --> K{"Erase Disk or Manual Partitioning?"}
K --> L["Set Computer Name / Username / Password"]
L --> M["Confirm Time Zone"]
M --> N["Run Installation (up to ~30 min)"]
N --> O["Boot into Installed Ubuntu VM"]
Getting Familiar with the Linux File System
Files on Linux are organized according to a stable, logical, hierarchical system that is consistent across virtually all Linux distributions, and largely holds true on macOS, OpenBSD, and Unix as well — even when resources are spread across multiple physical storage devices. This structure traces back many decades to the original Unix operating system.
This layout is formalized by the Filesystem Hierarchy Standard (FHS), documented by the Linux Foundation. Compliance requires that a distro provide each of the standard top-level directories under root — they don’t all need to be populated, but they must exist, so applications and users can rely on predictable locations across any compliant distro.
The very top of the file system is the root directory, represented by a single forward slash (/):
cd /
Listing its contents shows the standard top-level directories, plus possibly a few extras created by regular system use:
ls
Note: a directory literally named root (the home directory of the root user) is not the same thing as “the root directory” — it is just one subdirectory located directly under root.
flowchart TD
ROOT["/ (root directory)"]
ROOT --> BIN["/bin -> symlink to /usr/bin"]
ROOT --> SBIN["/sbin -> symlink to /usr/sbin"]
ROOT --> BOOT["/boot"]
ROOT --> DEV["/dev"]
ROOT --> ETC["/etc"]
ROOT --> HOME["/home"]
ROOT --> LIB["/lib"]
ROOT --> MEDIA["/media"]
ROOT --> MNT["/mnt"]
ROOT --> OPT["/opt"]
ROOT --> PROC["/proc"]
ROOT --> ROOTUSR["/root (root user's home dir)"]
ROOT --> RUN["/run"]
ROOT --> USR["/usr"]
ROOT --> VAR["/var"]
USR --> USRBIN["/usr/bin"]
USR --> USRLIB["/usr/lib"]
USR --> USRSHARE["/usr/share"]
Most of these directories form their own tree-like substructures. The tree command visualizes that structure directly:
tree -L 1
tree may not be installed by default. On Debian/Ubuntu systems, install it with:
sudo apt update
sudo apt install tree
Running tree with no depth limit against a full system illustrates just how large Linux file systems can get — commonly more than 64,000 directories containing more than half a million files (this count can be inflated by large development environments, e.g. a Python/JupyterLab installation):
tree
Moving into /etc:
cd /etc
Because the current location is already root, the leading slash could be omitted here — but in general, including the leading slash ensures Linux resolves the path relative to root rather than the current directory.
A shell alias may let a shortened command work — for example, a Bash configuration might map a single letter l to ls. This is a per-system/per-user convenience and should not be assumed to work everywhere.
/etc is a very active directory holding most system and application configuration files, so it tends to accumulate many subdirectories and files quickly.
Confirming your location and command locations:
pwd
To find where a command’s actual binary file lives:
which pwd
# /usr/bin/pwd
To understand why a command can be run without specifying its full path, inspect the PATH environment variable:
echo $PATH
PATH is a colon-separated list of directories that are searched, in order, whenever a bare command name is typed — as though invoking the command from inside one of those directories. If /usr/bin (where pwd lives) is not in PATH, or if a binary is moved out of a directory listed in PATH, invoking it by name alone will fail. New directories can be manually appended to PATH as needed — a common task for Linux administrators.
flowchart LR
CMD["User types: pwd"] --> SHELL["Shell checks $PATH directories in order"]
SHELL --> D1["/usr/local/sbin"]
SHELL --> D2["/usr/local/bin"]
SHELL --> D3["/usr/bin"]
D3 --> FOUND["Binary found: /usr/bin/pwd"]
FOUND --> EXEC["Command executes"]
Moving Around the Linux File System
Linux command interpretation depends heavily on whether a path is absolute (starts from root) or relative (interpreted based on the current directory).
Example: from inside /etc/perl, running:
cd home
fails, because Linux looks for a directory literally named home beneath the current directory (/etc/perl/home), which does not exist. Prefixing the path with a slash resolves it from the true root instead:
cd /home
pwd
/home is where user accounts get their own personal directories — for example, a default ubuntu user account would have its personal working space at /home/ubuntu. It is common practice to create a private directory hierarchy under /home for every new user added to a system.
Relative navigation also works with .. (parent directory):
cd ..
pwd
Key root-level directories:
| Directory | Purpose |
|---|---|
/bin | Binaries for essential user commands (cat, chmod, mkdir, etc.) — actually a symbolic link into /usr/bin on modern systems |
/sbin | Binaries for system-oriented tools used more by Linux itself (process, network, firewall, encryption tasks) — a symbolic link into /usr/sbin |
/usr | Contains system resources, including /usr/share (static docs and locale data needed by all processes/users) and the real locations backing /bin//sbin |
/etc | System and application configuration files |
/lib | Shared libraries and kernel module files — libraries hold reusable code functions for any process; modules extend kernel device support without rebooting |
/media, /mnt | Mount points for removable media (USB drives) and temporary file systems; normally empty unless a device has been manually mounted |
/var | Variable data generated by the system and running applications, including log files; also conventionally used by tools like web servers for their application files |
/dev | Dynamic files representing physical devices recognized by the system; generated in response to detected hardware and not guaranteed to persist across reboots |
Verifying that /bin and /sbin are really symlinks:
ls -l /bin
ls -l /sbin
This design reflects the historical transition from systems with very limited storage to today’s resource-rich environments, where /usr now holds the canonical binary locations and /bin//sbin remain only for compatibility.
Module 3: Working with Files and Directories
Reading Files from the Command Line
Since Linux is fundamentally driven by plaintext configuration and data files, a solid toolkit for reading and working with text from the command line is essential.
cat prints file contents to the screen:
cat /etc/shells
/etc/shells lists the file-system locations of each shell interpreter currently available on the system. A leading line beginning with # is a comment meant only for human readers — programs ignore it. Different shell interpreters can interpret certain commands slightly differently, which is why the available options are tracked in this file (even though most users colloquially just call their shell “Bash,” regardless of the actual interpreter in use).
Print with line numbers (useful when, say, an error message references a specific line number):
cat -n /etc/shells
Clear the screen (same role as cls on Windows):
clear
cat is short for concatenate — its core purpose is to link/chain the contents of multiple sources together, not just print a single file:
cat /etc/shells /etc/passwd
/etc/passwd (spelled without the “o” and “r” you might expect) holds login information for each system user. Encrypted password data used to live here too, but was moved to a separate /etc/shadow file years ago for security reasons. Running the combined cat command above prints the contents of /etc/shells first, immediately followed by the (much longer) contents of /etc/passwd. cat is also efficient for combining large data files — for example, concatenating multiple large CSV files (millions of rows) into a single file, a task at which cat is hard to beat for speed and reliability.
cat is convenient for short files, but not for files that extend beyond a single screen — like /etc/passwd, and more so, system logs.
less is suited for browsing longer files interactively. Listing the log directory first:
ls /var/log
auth.log— records of account authentication attempts.- Files under an
apache2subdirectory — events related to the Apache web server. syslog— on Debian/Ubuntu systems, this captures events from most system log producers, and is typically a very long file.
Open a long file with less:
less /var/log/syslog
Each log entry typically begins with a datetime stamp, followed by the process name and event message.
less Key | Action |
|---|---|
Space | Move down one screen |
b | Move back up one screen |
/searchterm | Search forward for a string (case-sensitive) |
n | Jump to the next match |
G (uppercase) | Jump to the end of the file |
q | Quit less |
Example search inside less: typing /Error (capital E, since the search is case-sensitive) and pressing Enter jumps to the first match; n cycles through subsequent matches, with matches highlighted.
head and tail extract just the lines you need from large files, rather than displaying everything.
head /var/log/syslog # first 10 lines (default)
head -n 5 /var/log/syslog # first 5 lines
tail /var/log/syslog # last 10 lines (default)
| Command | Purpose | Common Flags |
|---|---|---|
cat | Print (and concatenate) whole file contents | -n (number lines) |
less | Interactively page through long files, with search | /pattern, n, G, q |
head | Print the first lines of a file | -n N (first N lines) |
tail | Print the last lines of a file | -n N (last N lines), -f (follow) |
Creating and Editing Files Using Nano
Creating and editing files is just as important as reading them. Full-featured word processors — Microsoft Word, Google Docs, or even the open-source LibreOffice Writer — should generally be avoided for Linux administration tasks, because they add invisible formatting markup by default that can cause a Bash script or configuration file to behave erratically or fail outright. Linux administration requires truly plain text.
Options include a graphical plaintext editor (e.g., gedit) or a terminal-based editor. Historically that meant vi (or its modern successor, vim) — originally designed for terminals with very limited keyboards (no mouse, no arrow keys or function keys in the earliest environments). This led to navigation via regular character keys and multiple editing modes; even exiting vi requires a specific key sequence (:q). While vi/vim is extremely powerful once mastered, it has a steep learning curve.
Many administrators prefer nano instead, a simpler terminal-based text editor:
nano newfile.txt
If the named file already exists, its contents load into the editor; otherwise, nano opens an empty buffer. A mouse cannot be used, but arrow keys work normally, and a menu of key combinations is shown at the bottom of the screen.
| Nano Shortcut | Action |
|---|---|
Ctrl+X | Exit (prompts to save unsaved changes) |
Ctrl+O | Save (write out) without exiting |
Ctrl+Shift+V | Paste (regular Ctrl+V/Ctrl+C often do not work in Bash shells; right-click copy/paste generally does work) |
Typing content and pressing Ctrl+X, then Y to confirm saving, writes the new file to the current directory; cat newfile.txt then shows the saved content.
Editing a system file that requires elevated privileges: attempting to edit /var/log/syslog directly with nano may show a warning that the file is unwritable, because syslog is readable by any user but writable only by users with root privileges:
nano /var/log/syslog
Opening it with elevated privileges (assuming your user is a member of the sudo group) would allow saving changes:
sudo nano /var/log/syslog
Without sudo, attempting to save (Ctrl+X, then confirming with Enter) fails; choosing N at the save prompt discards the attempted changes instead.
Editing a file you own (for example, an old script file owned by your own user account) works normally — arrow keys move between lines, Delete removes characters. A practical example from the narration: editing a script to uncomment previously commented-out lines (removing a leading # and following space) so that a pip install command and other previously disabled commands will actually execute when the script runs, and adding an exit command at the end to terminate the script explicitly. Saving with Ctrl+X (confirming Y) writes the changes to disk without any permission warnings, since the file belongs to the current user.
Monitoring Ongoing File Changes
Piping commands together. The pipe character (|, typically Shift + backslash) sends the output of one command directly into another command as input, rather than printing it to the screen:
cat file.txt | head -n 20
This is functionally equivalent to head -n 20 file.txt. Chaining a second pipe extracts a very specific slice of a file — for example, lines 16 through 20:
cat file.txt | head -n 20 | tail -n 5
flowchart LR
A["cat file.txt"] -->|pipe| B["head -n 20"]
B -->|pipe| C["tail -n 5"]
C --> D["Lines 16-20 printed"]
Building and running a shell script. Using nano to create a new script:
nano myscript.sh
While Linux does not require a specific file extension to determine how to execute a file, .sh is a common convention to signal “this is a shell script” for human readability. An illustrative log-generating script discussed in the narration behaves like this:
#!/bin/bash
# Generates fake log entries to simulate a running application
while true; do
echo "$(date '+%Y-%m-%d %H:%M:%S') INFO: sample log entry 1" >> webapp.log
sleep 2
echo "$(date '+%Y-%m-%d %H:%M:%S') INFO: sample log entry 2" >> webapp.log
sleep 1
echo "$(date '+%Y-%m-%d %H:%M:%S') INFO: sample log entry 3" >> webapp.log
sleep 2
done
The script’s while loop repeatedly executes a small set of commands (in this example, three echo statements interleaved with sleep pauses) until something breaks the loop, appending each generated entry to a log file (webapp.log) in the current directory.
Before the script can run, it needs the executable permission bit set:
chmod +x myscript.sh
ls -l myscript.sh
Many shells will color an executable file differently (e.g., green) once the executable bit is set, as a visual convenience (not guaranteed across all shell configurations).
Running the script, using a leading ./ to tell Bash the file lives in the current directory, and & to run it as a background process (so the terminal remains available):
./myscript.sh &
Because the script’s output is redirected into webapp.log rather than the terminal, nothing prints to the screen immediately. Confirming the file exists and inspecting its growing contents:
ls
cat webapp.log
Re-running the last command without retyping it is possible using the Up arrow key to recall command history.
Following a growing file with tail -f. Rather than repeatedly re-running cat, the -f (“follow”) flag on tail continuously prints new lines as they are appended:
tail -f webapp.log
This immediately shows the most recent lines of the existing file, then streams new lines as they are written — useful, for example, to watch a service’s error log in near-real time without manually scrolling through potentially thousands of boring log entries. Press Ctrl+C to stop following.
Managing a backgrounded process. To bring a background job back to the foreground (so it can be interrupted), use fg with the job number:
fg %1
Once back in the foreground, Ctrl+C stops the process.
stateDiagram-v2
[*] --> Foreground: script started normally
Foreground --> Background: append & to command, or Ctrl+Z then bg
Background --> Foreground: fg %<job_number>
Foreground --> Terminated: Ctrl+C
Background --> Terminated: kill <pid>
Accessing System Documentation
Linux administration leaves little room for error — a single wrong character can cause a command to fail outright, or (worse) to succeed in an unintended way, up to and including permanently and irreversibly erasing data from a drive. Getting commands right matters, and Linux provides substantial built-in documentation to help.
Bare command guidance. Running a command with no arguments sometimes prints basic usage guidance:
tar
Many tools also support explicit help flags:
tar --help
tar --usage
Piping long help output into less keeps it manageable:
tar --help | less
(tar itself is used to bundle multiple files into a single archive file, or unpack an existing archive, optionally applying compression/decompression.)
The man system. The primary source of documentation for most commands is their manual page:
man tar
A typical man page:
- Notes that
tarsupports both the traditional Linux/GNU syntax (no dash required before flags) and the older Unix-style syntax (dash required) — reflecting the tool’s age (tardates back to the 1970s). - Provides a detailed description of the tool and its usage.
- Explains each flag/option in detail.
- Is divided into consistent sections, often including practical examples, external references, copyright information, and sometimes historical/biographical notes about the original authors.
Man page section numbers. Man pages are organized into numbered sections; the same command name can have entries in multiple sections covering different topics:
man kill # defaults to section 1 (User Commands)
man 1 kill # explicitly: User Commands Manual
man 2 kill # System Calls Manual (a completely different guide, still about "kill")
man 3 kill # (may report no section 3 exists for kill)
| Man Section Number | Content Type |
|---|---|
| 1 | User Commands |
| 2 | System Calls |
| 3 | Library Calls |
| 4 | Special Files (e.g., device files) |
| 5 | File Formats and Conventions |
| 6 | Games |
| 7 | Miscellaneous (macros, conventions, protocols) |
| 8 | System Administration Commands |
A command can have up to 8 separate man pages (one per section), though most commands only have one.
Searching man pages by keyword. When the exact command name isn’t known, -k searches man page name descriptions for a keyword:
man -k "delete a directory"
This might surface rmdir (deletes a directory, but only if it is already empty) even when the actual goal was rm (deletes files or directories, including non-empty ones) — because the rm man page’s name section happens to use the word “remove” rather than “delete.” This illustrates why it can be necessary to experiment with different search terms when searching man pages by keyword.
flowchart TD
Q["Need help with a command"] --> A{"Do you know the command name?"}
A -->|Yes| B["man <command>"]
A -->|No| C["man -k \"keyword phrase\""]
B --> D{"Multiple man sections for this name?"}
D -->|Yes| E["man <section_number> <command>"]
D -->|No| F["Single man page shown"]
C --> G["Review matching commands by description"]
Summary
Linux is built as a layered system: the kernel mediates between hardware and applications; the bootloader (GRUB) and init manager (systemd) bring the system to a running state; a distribution wraps the kernel together with an application layer, package manager, and configuration; and nearly everything on the system — configuration, logs, and application data — is represented as plaintext files organized under a standardized, predictable file system hierarchy.
Key principles to carry forward:
- The kernel is modular and portable across enormously different hardware, from smartphones to supercomputers, and is maintained as a large-scale collaborative open-source project.
- A distribution is more than a kernel — it is the kernel plus a curated application layer, package manager, and support model, and different distros exist to serve different needs (general-purpose desktop/server use, security testing, cloud-native deployment, enterprise support contracts, or minimal customizability).
- Open-source licensing comes with real (if usually minor) obligations; know whether software you depend on is permissive, copyleft, or public domain.
- The file system is organized predictably under a single root (
/), with well-known top-level directories (/etc,/home,/usr,/var,/bin,/sbin,/dev,/media,/mnt) serving consistent roles across distros. - Absolute paths (starting with
/) are unambiguous; relative paths depend on the current working directory — know the difference to avoidcdand file-access mistakes. - A small set of command-line tools (
cat,less,head,tail,nano, pipes,chmod,man) cover the overwhelming majority of everyday file-reading, file-editing, and troubleshooting needs. - Built-in documentation (
--help,man,man -k) should be the first stop before guessing at command syntax, given how unforgiving Linux administration can be of small mistakes.
Quick-Reference Command Table
| Command | Purpose |
|---|---|
pwd | Print current working directory |
ls | List directory contents |
cd <path> | Change directory (absolute path with /, relative without) |
tree -L 1 | Show directory structure one level deep |
which <cmd> | Show the file-system path of a command’s binary |
echo $PATH | Show directories searched for executable commands |
cat <file> | Print (or concatenate) file contents |
cat -n <file> | Print file contents with line numbers |
less <file> | Page through a long file interactively |
head -n N <file> | Print the first N lines of a file |
tail -n N <file> | Print the last N lines of a file |
tail -f <file> | Continuously follow a growing file |
nano <file> | Open a file in the nano text editor |
chmod +x <file> | Make a file executable |
./<script>.sh & | Run a script in the background |
fg %1 | Bring a background job back to the foreground |
man <command> | Open a command’s manual page |
man -k "<keyword>" | Search man page descriptions by keyword |
sudo <command> | Run a command with root privileges |
ssh user@host | Open a remote shell session over SSH |
Checklist for Getting Started with Linux
- Choose an installation method appropriate to your context (WSL, bootable USB, VM, or cloud instance).
- Learn to distinguish absolute vs. relative paths before navigating unfamiliar systems.
- Get comfortable with
cat,less,head, andtailfor reading files of any size. - Adopt a plaintext-safe editor (
nanoorvim) — never a word processor — for scripts and configuration files. - Understand file permissions well enough to use
chmodandsudocorrectly and safely. - Practice using
man(including-ksearch) before resorting to guesswork on unfamiliar commands.
Search Terms
linux · systems · administration · networking · security · system · command · installing · kernel