---
title: "100+ Essential Linux Commands You MUST Know (2026 Guide)"
description: "Master the Linux command line with this cheat sheet of 100+ essential Linux commands. Covers file management, networking, system admin, and modern CLI tools, all with practical examples for 2026."
date: 2026-07-31
categories: ["linux"]
tags: ["linux","linux-commands","bash"]
---

import Button from "@components/widgets/Button.astro";
import Notice from "@components/widgets/Notice.astro";
import ListCheck from "@components/widgets/ListCheck.astro";
import Accordion from "@components/widgets/Accordion.astro";
import Tabs from "@components/widgets/Tabs.astro";
import Tab from "@components/widgets/Tab.astro";

Whether you're a beginner or a seasoned sysadmin, knowing the right **Linux commands** can transform your workflow. This essential Linux commands cheat sheet covers over 100 commands, from basic file navigation to advanced system administration and modern CLI tools. It's the reference guide I wish I had when I started managing Linux servers, and the one I still keep bookmarked today.

Linux powers the majority of the world's servers, supercomputers, and cloud infrastructure. According to the Stack Overflow Developer Survey 2025, Bash/Shell is the 5th most popular language with 49% adoption. If you're running a [Hetzner VPS](https://go.bitdoze.com/hetzner), deploying Docker containers, or managing remote machines, these commands are your daily toolkit.

This guide is organized by task, not alphabetically. Each section covers what the commands do, how to use them, and what to watch out for. I've included verify steps after critical operations and called out common failure modes, the kind of stuff that saves you from a 2 AM incident.

<ListCheck>
<h5>What this guide covers</h5>
<ul>
<li>File management and navigation, the commands you use every minute</li>
<li>Text search and processing, grep, find, awk, sed and friends</li>
<li>File permissions and ownership, chmod, chown, and why 777 is never the answer</li>
<li>System monitoring and information, what's eating your CPU and disk</li>
<li>Process and service management, kill, systemctl, journalctl</li>
<li>Networking and remote access, SSH, firewalls, diagnostics</li>
<li>Package management, apt, dnf, pacman across distros</li>
<li>Shell productivity, aliases, history, pipes, and shortcuts</li>
<li>Scripting and automation, cron, systemd timers, bash basics</li>
<li>Developer and DevOps tools, git, docker, kubectl essentials</li>
<li>Modern CLI alternatives, faster Rust/Go replacements for classic tools</li>
</ul>
</ListCheck>

---

## Basic navigation and file management

These are the Linux commands you'll use in the first five minutes of any session. If you're new, start here.

### Navigating the filesystem (`pwd`, `ls`, `cd`)

#### `pwd` - print working directory

Shows where you are in the filesystem.

```bash
$ pwd
/home/username
```

#### `ls` - list directory contents

The most-run Linux command (seriously, it tops shell history analyses). Key flags:

- `-l`: Long listing with permissions, owner, size, date
- `-a`: Include hidden files (dotfiles)
- `-h`: Human-readable sizes (4.0K instead of 4096)
- `-R`: Recurse into subdirectories

```bash
$ ls
Desktop  Documents  Downloads  Music  Pictures  Videos

$ ls -lah
total 36K
drwxr-xr-x 5 username username 4.0K Jan 15 10:22 .
drwxr-xr-x 3 root    root    4.0K Jan 10 08:00 ..
-rw------- 1 username username  128 Jan 15 10:22 .bash_history
drwxr-xr-x 2 username username 4.0K Jan 10 08:01 Desktop
drwxr-xr-x 2 username username 4.0K Jan 10 08:01 Documents
```

#### `cd` - change directory

```bash
$ cd /var/log       # absolute path
$ cd ..             # up one level
$ cd ~/Documents    # ~ is your home directory
$ cd -              # back to previous directory
```

### File operations (`touch`, `cp`, `mv`, `rm`, `ln`)

#### `touch` - create empty file or update timestamp

```bash
$ touch newfile.txt
```

#### `cp` - copy files and directories

```bash
$ cp file1.txt file2.txt           # copy file
$ cp -r dir1/ dir2/                # copy directory recursively
$ cp -iv file1.txt file2.txt       # interactive + verbose
```

Verify with `ls -l` on the destination.

#### `mv` - move or rename

```bash
$ mv oldname.txt newname.txt       # rename
$ mv file.txt /path/to/dest/       # move
```

#### `rm` - remove files and directories

```bash
$ rm file.txt                      # remove file
$ rm -r directory/                 # remove directory recursively
$ rm -i *.log                      # interactive, asks before each delete
```

<Notice type="error" title="rm has no undo">
There is no trash can. `rm` deletes permanently. The classic footgun is `rm -rf $VAR/` when the variable `$VAR` is empty, that becomes `rm -rf /`. Always double-check variables. Consider `trash-cli` (`trash-put file.txt`) as a safer alternative for interactive use.
</Notice>

#### `ln` - create links

Links let you reference a file from another location without copying it.

```bash
$ ln -s /path/to/target link_name    # symbolic (soft) link
$ ln /path/to/target link_name       # hard link
```

Symbolic links are far more common. They're used everywhere in deployment setups, linking config files, pointing `/usr/local/bin` to your compiled binaries, etc.

### Archives and compression (`tar`, `gzip`, `zip`)

#### `tar` - the Swiss army knife of archives

The flag mnemonic: **c**reate, e**x**tract, **z** (gzip), **j** (bzip2), **f** (file).

```bash
# Create
$ tar -czf archive.tar.gz /path/to/dir/       # gzipped (most common)
$ tar -cjf archive.tar.bz2 /path/to/dir/      # bzip2 (smaller, slower)

# Extract
$ tar -xzf archive.tar.gz                     # extract gzipped
$ tar -xf archive.tar.gz                      # modern tar auto-detects compression

# List contents (always check before extracting)
$ tar -tzf archive.tar.gz | head
```

<Notice type="info" title="Modern tar auto-detects compression">
On any recent Linux distro, `tar -xf` works without `-z` or `-j`, it figures out the compression from the file header. So `tar -xf archive.tar.gz` is fine.
</Notice>

#### `gzip` / `gunzip` - standalone compression

```bash
$ gzip file.txt          # compresses file.txt → file.txt.gz (removes original)
$ gunzip file.txt.gz     # decompresses
```

#### `zip` / `unzip` - cross-platform archives

```bash
$ zip -r archive.zip directory/
$ unzip archive.zip
$ unzip archive.zip -d /destination/
```

---

## Viewing, searching, and editing files

### Viewing file contents (`cat`, `more`, `less`, `head`, `tail`)

```bash
$ cat file.txt                 # dump entire file to stdout
$ less file.txt                # paginated viewer (arrows, /search, q to quit)
$ head -20 file.txt            # first 20 lines
$ tail -20 file.txt            # last 20 lines
$ tail -f /var/log/syslog      # follow live, essential for log monitoring
```

`less` is almost always better than `cat` for reading. `cat` is for combining files or piping into other commands.

### Searching text (`grep`)

One of the top 5 most-used Linux commands. If you're not using `grep`, you're doing too much by hand.

```bash
$ grep "error" /var/log/syslog                # basic search
$ grep -r "password" /etc/                    # recursive search
$ grep -i "warning" file.txt                  # case-insensitive
$ grep -v "DEBUG" file.txt                    # invert, exclude matches
$ grep -n "TODO" *.py                         # show line numbers
$ grep -c "error" /var/log/syslog             # count matches
$ grep -E "err|warn|crit" file.txt            # extended regex (OR pattern)
$ grep -B2 -A3 "panic" logfile.txt            # 2 lines before, 3 after
$ ps aux | grep nginx                         # filter pipeline output
```

Verify with `grep -c` before doing any destructive operation based on matches.

### Finding files (`find`)

```bash
$ find . -name "*.txt"                        # by name
$ find . -type f -name "*.log"                # files only
$ find . -type d -name "node_modules"         # directories only
$ find . -mtime -7                            # modified in last 7 days
$ find . -size +100M                          # files larger than 100MB
$ find . -name "*.log" -delete                # delete matches (GNU find)
$ find . -name "*.txt" | xargs grep "error"   # find + grep combo
```

<Notice type="warning" title="Test find before using -exec or -delete">
`find . -name "*.log" -exec rm {} \;` is powerful and dangerous. Always test with `ls` first: `find . -name "*.log" -exec ls {} \;`. Also, start with `.` (current directory), not `/`, searching the entire filesystem is slow and noisy.
</Notice>

### Text processing (`sort`, `uniq`, `wc`, `cut`, `awk`, `sed`, `diff`)

These are pipeline tools, they shine when chained with `|`.

#### `sort` and `uniq`

```bash
$ sort file.txt                   # alphabetical sort
$ sort -n numbers.txt             # numeric sort
$ sort -r file.txt                # reverse
$ sort -k2 -t: data.txt           # sort by 2nd field, colon-delimited
$ sort file.txt | uniq            # remove adjacent duplicates (always sort first)
$ sort file.txt | uniq -c         # count occurrences
```

#### `wc` - word count

```bash
$ wc -l file.txt                  # line count
$ wc -w file.txt                  # word count
$ wc -c file.txt                  # byte count
```

#### `cut` - extract columns

```bash
$ cut -d':' -f1 /etc/passwd       # first field, colon-delimited
$ cut -c1-10 file.txt             # first 10 characters of each line
```

#### `awk` - pattern scanning and processing

```bash
$ awk '{print $1}' file.txt                   # first column
$ awk -F: '{print $1, $3}' /etc/passwd        # fields 1 and 3, colon-delimited
$ awk '$3 > 100' data.txt                     # lines where 3rd field > 100
```

#### `sed` - stream editor

```bash
$ sed 's/old/new/g' file.txt                  # replace all occurrences
$ sed -i 's/old/new/g' file.txt               # in-place edit (careful!)
$ sed -n '10,20p' file.txt                     # print lines 10-20
$ sed '/^#/d' config.txt                       # delete comment lines
```

#### `diff` - compare files

```bash
$ diff file1.txt file2.txt
$ diff -u file1.txt file2.txt                  # unified format (easier to read)
```

<Tabs>
<Tab name="Extract first column">
Using different tools to get the first colon-delimited field from `/etc/passwd`:

```bash
# Using cut
$ cut -d':' -f1 /etc/passwd

# Using awk
$ awk -F: '{print $1}' /etc/passwd

# Using sed
$ sed 's/:.*//' /etc/passwd
```

`cut` is simplest for fixed-delimiter data. `awk` is better when you need logic. `sed` is overkill here but works.
</Tab>
<Tab name="Count lines with 'error'">
```bash
# Using grep
$ grep -c "error" logfile.txt

# Using awk
$ awk '/error/ {count++} END {print count}' logfile.txt

# Using wc + grep
$ grep "error" logfile.txt | wc -l
```
</Tab>
</Tabs>

### Editors (`nano`, `vim`)

```bash
$ nano file.txt       # simple, beginner-friendly (Ctrl+X to exit)
$ vim file.txt        # powerful, steep learning curve (Esc then :wq to save+quit)
```

`vim` is worth learning because it's installed on virtually every Linux server. When you SSH into a fresh [Hetzner VPS](https://go.bitdoze.com/hetzner), `vim` is there. `nano` may not be.

---

## File permissions and ownership

### Understanding permissions

Every file has an owner, a group, and permissions for owner/group/others. Use `ls -l` to see them:

```
-rwxr-xr-- 1 alice developers 4096 Jan 15 10:00 deploy.sh
│└┬┘└┬┘└┬┘
│ │   │   └── others: read only (r--)
│ │   └────── group: read + execute (r-x)
│ └────────── owner: read + write + execute (rwx)
└──────────── regular file (-)
```

Numeric (octal) notation:

| Digit | Permissions | Meaning |
|-------|------------|---------|
| 7 | rwx | read + write + execute |
| 6 | rw- | read + write |
| 5 | r-x | read + execute |
| 4 | r-- | read only |
| 0 | --- | no permissions |

Common permission modes:

- `755`, owner full, everyone else read+execute (scripts, directories)
- `644`, owner read+write, everyone else read (config files, data)
- `600`, owner only (private keys, sensitive files)

### Changing permissions (`chmod`)

```bash
# Symbolic notation
$ chmod u+x script.sh          # add execute for owner
$ chmod g-w file.txt            # remove write for group
$ chmod a+r file.txt            # add read for everyone

# Numeric (octal) notation
$ chmod 755 script.sh           # rwxr-xr-x
$ chmod 644 config.txt          # rw-r--r--
$ chmod 600 ~/.ssh/id_ed25519   # rw------- (private key)
```

Verify after every change: `ls -l file`

<Notice type="error" title="Never chmod 777 in production">
`chmod 777` gives everyone full access. On SSH keys, it's even worse, SSH will refuse to use a private key with open permissions. You'll get "Permissions 0664 for 'id_ed25519' are too open." Fix: `chmod 600 ~/.ssh/id_ed25519`.
</Notice>

### Changing ownership (`chown`, `chgrp`)

```bash
$ chown user:group file.txt
$ chown -R www-data:www-data /var/www/    # recursive (common for web servers)
$ chgrp developers project/               # change group only
```

---

## System information and monitoring

### System info (`uname`, `hostname`, `uptime`, `free`, `dmesg`)

```bash
$ uname -a                    # all system info (kernel, arch, etc.)
$ uname -r                    # kernel release only
$ hostname                    # machine hostname
$ uptime                      # how long running + load averages
$ free -h                     # memory usage in human-readable format
$ dmesg | tail                # kernel ring buffer (hardware/driver issues)
```

`free -h` and `df -h` are the first two commands I run when a VPS feels slow or misbehaves. They tell you in seconds whether it's a memory or disk problem.

Want to go deeper on monitoring? See how to [monitor CPU usage and send email alerts](/monitor-cpu-usage-and-send-email-alerts-in-linux) for proactive alerting.

### Disk usage (`df`, `du`)

```bash
$ df -h                       # filesystem disk space overview
$ du -sh /var/log             # total size of /var/log
$ du -sh /*                   # size of each top-level directory
$ du -sh /var/* | sort -h     # find the biggest directory under /var
```

<Notice type="info" title="Disk full on your VPS?">
Quick troubleshooting sequence:
1. `df -h` — which filesystem is full?
2. `du -sh /*` — which top-level dir is the hog?
3. `du -sh /var/*` — drill down
4. `journalctl --disk-usage` — systemd journals eating disk?
5. `apt autoremove && apt clean` — reclaim package cache
6. `journalctl --vacuum-size=500M` — cap journal size

For a deep-dive on disk imaging and cloning, see the [dd command guide](/linux-dd-command-guide).
</Notice>

### Listing block devices (`lsblk`, `blkid`)

```bash
$ lsblk                       # list all block devices and mount points
$ blkid                       # show UUIDs (needed for /etc/fstab entries)
```

These are essential when adding extra volumes to a VPS.

---

## User and group management

### User commands (`whoami`, `id`, `useradd`, `usermod`, `passwd`, `userdel`)

```bash
$ whoami                      # current username
$ id                          # current user's UID, GID, and groups
$ sudo useradd -m -s /bin/bash newuser      # create user with home dir
$ sudo usermod -aG sudo newuser             # add to sudo group
$ sudo passwd newuser                       # set password
$ sudo userdel -r olduser                   # delete user + home directory
```

<Notice type="info" title="sudo — running commands as root">
Prefix any command with `sudo` to run it as root. Most system administration commands require it. Use `sudo -i` for a full root shell. Use `sudo !!` to re-run the last command with sudo prepended (handy when you forget).
</Notice>

Failure mode: `userdel` without `-r` leaves the home directory behind. Always use `userdel -r` to clean up.

### Group commands (`groupadd`, `groupdel`, `groups`, `who`)

```bash
$ sudo groupadd newgroup       # create group
$ sudo groupdel oldgroup       # delete group
$ groups                       # show current user's groups
$ who                          # who is logged in
$ w                            # who is logged in and what they're doing
```

---

## Process management

### Viewing processes (`ps`, `top`, `htop`)

```bash
$ ps aux                       # all processes, BSD format
$ ps -ef                       # all processes, full format
$ ps -u username               # processes for a specific user
$ top                          # real-time process viewer (press q to quit)
$ htop                         # interactive, user-friendly top (may need install)
```

When `top` or `htop` shows high memory, check [swap usage](/swap-usage-linux) to see if processes are being swapped out.

### Managing processes (`kill`, `killall`, `pkill`, `bg`, `fg`, `nohup`, `jobs`)

<Notice type="warning" title="Always try SIGTERM first">
`kill PID` sends SIGTERM (signal 15) — a polite request to exit. The process can catch it, clean up temp files, close connections, and shut down gracefully. Only use `kill -9 PID` (SIGKILL) as a last resort — it can't be caught or ignored, and the process gets no chance to clean up.
</Notice>

```bash
$ kill PID                     # SIGTERM — polite shutdown (default signal)
$ kill -9 PID                  # SIGKILL — force kill, last resort
$ kill -l                      # list all signal names
$ killall processname           # kill all processes by name (SIGTERM)
$ pkill -f "pattern"           # kill by matching full command line
```

Background jobs:

```bash
$ long_running_command &
$ jobs                         # list background jobs
$ fg %1                        # bring job 1 to foreground
$ bg %1                        # resume job 1 in background
$ nohup ./server.sh &          # keep running after you log out (essential for VPS)
```

Verify after killing: `ps aux | grep processname` — make sure it's gone.

Failure modes:
- Never `kill -9` PID 1 (init/systemd) — kernel panic or system hang.
- `killall nginx` kills *all* nginx processes. Be specific.

### Process priority (`nice`, `renice`)

```bash
$ nice -n 10 ./heavy_task.sh         # start with lower priority (nicer)
$ renice -n 5 -p PID                 # change priority of running process
```

Priority range: -20 (highest) to 19 (lowest). Default is 0.

---

## Service management with systemd

`systemctl` and `journalctl` are how you manage services on any modern Linux distro. This section was completely missing from the original article — and it's the first thing you need when a service won't start.

### Managing services (`systemctl`)

```bash
$ systemctl status nginx            # check service status
$ systemctl start nginx             # start now
$ systemctl stop nginx              # stop now
$ systemctl restart nginx           # restart
$ systemctl enable nginx            # start at boot
$ systemctl disable nginx           # don't start at boot
$ systemctl enable --now nginx      # enable + start (common pattern)
$ systemctl disable --now nginx     # disable + stop
$ systemctl list-units --state=failed   # see all failed services
$ systemctl daemon-reload           # reload unit files after editing
```

<Notice type="info" title="enable vs start">
`systemctl start nginx` starts the service right now. `systemctl enable nginx` makes it start automatically at boot. You usually want both: `systemctl enable --now nginx`.
</Notice>

Verify after any restart: `systemctl status nginx` and `journalctl -u nginx --since "1 min ago"`.

Failure mode: `systemctl disable` without `systemctl stop` means the service runs until the next reboot but won't start after that. Confusing. Use `disable --now`.

### Viewing logs (`journalctl`)

```bash
$ journalctl -u nginx                 # logs for nginx
$ journalctl -u nginx -f              # follow live (like tail -f)
$ journalctl -u nginx --since "1 hour ago"
$ journalctl -p err                   # only errors across all services
$ journalctl --disk-usage             # how much disk are journals using?
$ journalctl --vacuum-size=500M       # cap journal size at 500MB
```

<Notice type="info" title="Journals can eat your disk">
On long-running VPS instances, systemd journals can silently grow to several gigabytes. Use `journalctl --disk-usage` to check. Set a cap in `/etc/systemd/journald.conf` with `SystemMaxUse=500M`, or use `journalctl --vacuum-size=500M` to trim.
</Notice>

---

## Networking and remote access

### Connectivity and diagnostics (`ping`, `traceroute`, `dig`, `nc`)

```bash
$ ping -c 4 google.com                # send 4 packets
$ traceroute google.com               # trace network path
$ dig bitdoze.com                     # DNS lookup (A record)
$ dig bitdoze.com MX                  # mail exchanger records
$ nc -zv host.example.com 22          # test if port 22 is open
$ nc -zv host.example.com 443         # test HTTPS port
```

`dig` is more powerful than `nslookup` and gives cleaner output. `nc` (netcat) is invaluable for debugging "can't connect" issues.

### Network configuration (`ip`, `ss`)

<Notice type="warning" title="net-tools may not be installed">
`ifconfig` and `netstat` are part of the deprecated `net-tools` package. They're removed from RHEL 9 default install and not in minimal Ubuntu 24.04. If you run `ifconfig` and get "command not found," that's why. Use `ip` and `ss` instead — they're more powerful and always available.
</Notice>

```bash
$ ip a                            # show all IP addresses (replaces ifconfig)
$ ip link                         # show network interfaces
$ ip route                        # show routing table
$ ss -tuln                        # show listening TCP/UDP ports (replaces netstat)
$ ss -tp                          # show established connections with process names
```

`ss -tuln` is the modern way to check what's listening. It's faster than `netstat` and doesn't need a separate package.

### Remote access (`ssh`, `ssh-keygen`, `scp`, `sftp`, `rsync`)

#### SSH basics

```bash
$ ssh user@remote-host                        # connect
$ ssh -p 2222 user@remote-host                # custom port
$ ssh -i ~/.ssh/my_key user@remote-host       # specific key
$ ssh -L 8080:localhost:80 user@remote-host   # local port forwarding
```

#### SSH keys

```bash
$ ssh-keygen -t ed25519 -C "your_email@example.com"
$ ssh-copy-id user@remote-host                # copy public key to server
```

<Notice type="info" title="Use Ed25519 keys, not RSA">
Always generate Ed25519 keys (`ssh-keygen -t ed25519`). They're shorter, faster, and more secure than RSA. RSA 2048-bit keys are considered weak by modern standards. Ed25519 is the default on all modern OpenSSH versions.
</Notice>

Verify: `ls -la ~/.ssh/` after keygen. Test passwordless login with `ssh user@remote-host`.

Failure mode: `chmod 777` on SSH private key → SSH refuses it. Always `chmod 600 ~/.ssh/id_*`.

For more on hardening SSH, see [securing your SSH server](/secure-ssh-server-linux).

#### File transfer (`scp`, `sftp`, `rsync`)

```bash
$ scp file.txt user@remote:/path/                    # copy to remote
$ scp user@remote:/path/file.txt ./                   # copy from remote
$ sftp user@remote                                    # interactive file transfer
$ rsync -avz /local/dir/ user@remote:/path/           # sync directories
$ rsync -avz --delete /src/ /dest/                    # mirror (deletes extras)
```

`rsync -avz` is my default for any file sync. It only transfers changed files, compresses in transit, and preserves permissions.

### Firewalls (`ufw`, `firewall-cmd`, `iptables`/`nftables`)

<Tabs>
<Tab name="ufw (Ubuntu/Debian)">
```bash
$ sudo ufw allow 22/tcp               # allow SSH
$ sudo ufw allow 443/tcp              # allow HTTPS
$ sudo ufw enable                     # activate firewall
$ sudo ufw status verbose             # show rules
```
</Tab>
<Tab name="firewall-cmd (RHEL/Fedora)">
```bash
$ sudo firewall-cmd --permanent --add-service=ssh
$ sudo firewall-cmd --permanent --add-service=https
$ sudo firewall-cmd --reload
$ sudo firewall-cmd --list-all
```
</Tab>
<Tab name="iptables (low-level)">
```bash
$ sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
$ sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
$ sudo iptables -L -n -v
```

Note: `iptables` rules are lost on reboot unless saved with `iptables-save`. On modern distros, `nftables` is the kernel backend — `iptables` commands work via a compatibility layer.
</Tab>
</Tabs>

<Notice type="error" title="Never flush firewall rules on a remote VPS">
`iptables -F` deletes all rules, including the one allowing your SSH connection. You'll lock yourself out. Always ensure SSH (port 22) is allowed before applying new rules.
</Notice>

---

## Package management

### Debian/Ubuntu (`apt`)

```bash
$ sudo apt update                 # refresh package index
$ sudo apt upgrade                # upgrade installed packages
$ sudo apt install nginx          # install a package
$ sudo apt remove nginx           # remove (keeps config)
$ sudo apt purge nginx            # remove package AND config
$ sudo apt autoremove             # remove unused dependencies
$ sudo apt search keyword         # search for packages
$ sudo apt show nginx             # package details
```

<Notice type="info" title="apt vs apt-get">
`apt` is for interactive terminal use — it has progress bars and color output. `apt-get` is for scripts and Dockerfiles where you want stable, parseable output between versions. Use `apt` at the terminal, `apt-get` in your CI pipelines.
</Notice>

### RHEL/Fedora (`dnf` / `dnf5`)

Fedora 41 (October 2024) made DNF5 the default package manager. RHEL 9 and CentOS Stream 9 still use `dnf` (v4). The commands are the same:

```bash
$ sudo dnf install nginx
$ sudo dnf update
$ sudo dnf remove nginx
$ sudo dnf search keyword
```

`yum` is effectively dead on modern systems. If you're still using it, switch to `dnf`.

### Other package managers

```bash
# Arch Linux
$ sudo pacman -S package_name         # install
$ sudo pacman -Syu                    # update all
$ sudo pacman -R package_name         # remove

# openSUSE
$ sudo zypper install package_name
$ sudo zypper update

# Flatpak (cross-distro)
$ flatpak install flathub org.app.Name
$ flatpak update

# Snap (Ubuntu/Canonical)
$ sudo snap install package_name
$ snap list
```

<Tabs>
<Tab name="Install a package">
```bash
# Debian/Ubuntu
sudo apt install nginx

# RHEL/Fedora
sudo dnf install nginx

# Arch
sudo pacman -S nginx

# openSUSE
sudo zypper install nginx
```
</Tab>
<Tab name="Update all packages">
```bash
# Debian/Ubuntu
sudo apt update && sudo apt upgrade

# RHEL/Fedora
sudo dnf upgrade

# Arch
sudo pacman -Syu

# openSUSE
sudo zypper update
```
</Tab>
</Tabs>

---

## Disk and storage management

### Partitioning (`fdisk`, `parted`)

```bash
$ sudo fdisk /dev/sda             # MBR partitioning (interactive)
$ sudo parted /dev/sda            # GPT partitioning (for disks >2TB)
```

<Notice type="error" title="Double-check the disk!">
`fdisk` on the wrong disk = irreversible data loss. Always run `lsblk` first to confirm which disk is which. Once you press `w` (write) in fdisk, there's no undo.
</Notice>

### Filesystems (`mkfs`, `mount`, `umount`, `fsck`)

```bash
$ sudo mkfs.ext4 /dev/sda1        # create ext4 filesystem
$ sudo mount /dev/sda1 /mnt       # mount
$ sudo umount /mnt                # unmount
$ sudo fsck /dev/sda1             # check filesystem for errors
```

For mounting [NFS shares](/setup-nfs-linux) on a network, use `mount -t nfs server:/share /mnt/nfs`.

To make mounts persistent across reboots, add entries to `/etc/fstab` (use `blkid` to get UUIDs).

---

## Shell productivity and history

### Command shortcuts (`alias`, `history`, `!!`, `!$`)

```bash
$ alias ll='ls -la'              # create shortcut
$ alias                          # list all aliases
$ history                        # show command history
$ history | grep docker          # search history
$ !!                             # repeat last command (useful with sudo: sudo !!)
$ !$                             # last argument of previous command
```

Press `Ctrl+R` for reverse incremental search through history. Start typing and it finds matching commands.

For a better experience, set up [command autocomplete in Zsh](/enable-command-autocomplete-in-zsh) and [syntax highlighting in Zsh](/enable-syntax-highlighting-zsh).

### Pipes, redirects, and utilities (`tee`, `xargs`, `watch`, `export`, `env`, `source`)

```bash
$ command | tee output.log        # write to file AND stdout
$ find . -name "*.tmp" | xargs rm    # build rm command from stdin
$ watch -n 2 docker ps           # repeat every 2 seconds (great for monitoring)
$ export VAR=value                # set environment variable
$ env                             # list all environment variables
$ source ~/.bashrc                # reload shell config without restarting terminal
```

<Notice type="info" title="The power of pipes">
The real power of Linux commands comes from combining them with pipes (`|`). Each command does one thing well — chain them together:

```bash
$ ps aux | grep nginx | awk '{print $2}' | xargs kill
```

This finds all nginx processes, extracts their PIDs, and kills them. One line.
</Notice>

---

## Scripting and automation

### Shell scripting basics

```bash
#!/bin/bash
echo "Starting backup..."
DATE=$(date +%Y%m%d)
tar -czf /backups/backup_$DATE.tar.gz /data/
echo "Backup complete: backup_$DATE.tar.gz"
```

Key constructs:

```bash
# Variables
name="World"
echo "Hello, $name!"

# Conditionals
if [ -f /tmp/lockfile ]; then
    echo "Lock file exists"
elif [ -d /tmp/workdir ]; then
    echo "Working directory found"
else
    echo "Clean state"
fi

# For loop
for file in *.log; do
    echo "Processing $file"
done

# While loop
count=1
while [ $count -le 5 ]; do
    echo "Count: $count"
    count=$((count + 1))
done
```

### Task scheduling (`cron`, `at`)

The crontab syntax diagram:

```
* * * * * command_to_execute
- - - - -
| | | | |
| | | | +----- Day of week (0-7, Sunday = 0 or 7)
| | | +------- Month (1-12)
| | +--------- Day of month (1-31)
| +----------- Hour (0-23)
+------------- Minute (0-59)
```

```bash
$ crontab -e                              # edit your crontab
$ crontab -l                              # list current cron jobs

# Examples:
0 2 * * * /path/to/backup.sh              # every day at 2 AM
*/5 * * * * /path/to/healthcheck.sh       # every 5 minutes
0 0 * * 0 /path/to/weekly_cleanup.sh      # every Sunday at midnight
```

```bash
$ at 2:00 PM                              # one-time scheduled job
at> /path/to/script.sh
at> <Ctrl+D>
```

### systemd timers (modern alternative to cron)

systemd timers offer better logging, dependency management, and random delay support. They're the modern approach on all systemd-based distros.

```ini
# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup timer

[Timer]
OnCalendar=*-*-* 02:00:00
RandomizedDelaySec=900
Persistent=true

[Install]
WantedBy=timers.target
```

```ini
# /etc/systemd/system/backup.service
[Unit]
Description=Run backup

[Service]
Type=oneshot
ExecStart=/path/to/backup.sh
```

```bash
$ sudo systemctl enable --now backup.timer
$ systemctl list-timers                     # see all active timers
```

<Notice type="info" title="cron vs systemd timers">
cron is simpler and universally understood. systemd timers offer better logging (`journalctl -u backup`), dependency management, and `RandomizedDelaySec` to avoid thundering herd problems. For simple tasks, cron is fine. For anything that depends on other services, consider systemd timers.
</Notice>

---

## Developer and DevOps tools

### Version control (`git`)

Git is used by 93.87% of developers (Stack Overflow 2025). These are the commands you'll use daily:

```bash
$ git init                            # initialize new repo
$ git clone https://github.com/...    # clone remote repo
$ git status                          # what's changed?
$ git add .                           # stage all changes
$ git commit -m "message"             # commit staged changes
$ git push                            # push to remote
$ git pull                            # pull from remote
$ git log --oneline                   # compact history
$ git diff                            # see unstaged changes
```

For a comprehensive deep-dive, see [Git commands](/git-commands).

### Containers (`docker`)

Docker has 71.1% adoption among developers (Stack Overflow 2025). These are the most-used commands:

```bash
$ docker run -d -p 80:80 nginx        # run container in background
$ docker ps                           # list running containers
$ docker ps -a                        # list all containers (including stopped)
$ docker logs container_name          # view logs
$ docker exec -it container_name bash # shell into running container
$ docker stop container_name          # stop
$ docker rm container_name            # remove stopped container
$ docker images                       # list images
$ docker compose up -d                # start compose stack
$ docker compose down                 # stop and remove compose stack
```

For the full reference, see [Docker commands](/docker-commands).

### Container orchestration (`kubectl`)

If you're running Kubernetes:

```bash
$ kubectl get pods                    # list pods
$ kubectl logs pod_name               # view pod logs
$ kubectl exec -it pod_name -- bash   # shell into pod
$ kubectl apply -f manifest.yaml      # apply configuration
$ kubectl get services                # list services
```

This is only relevant if you're running K8s — skip it if you're using Docker Compose or a PaaS.

---

## Modern CLI alternatives

### Why use modern tools?

Over the past few years, developers have rewritten many classic Unix tools in Rust and Go. The results are faster, prettier, and often more ergonomic. The tradeoff: they need installation, while legacy tools are always available on a minimal VPS.

If you manage servers for a living, these tools are worth the install time. If you're writing a Dockerfile that needs to work everywhere, stick with the classics.

### The modern toolkit

| Legacy Tool | Modern Alternative | Key Benefit |
|------------|-------------------|-------------|
| `cat` | [bat](https://github.com/sharkdp/bat) | Syntax highlighting, line numbers, git integration |
| `ls` | [eza](https://github.com/eza-community/eza) | Colors, icons, tree view, git awareness |
| `cd` | [zoxide](https://github.com/ajeetdsouza/zoxide) | Remembers frequent dirs, jump with partial names |
| `grep` | [ripgrep (rg)](https://github.com/BurntSushi/ripgrep) | Faster, respects .gitignore, clean output |
| `find` | [fd](https://github.com/sharkdp/fd) | Intuitive syntax, faster, colorized |
| `top`/`htop` | [btop](https://github.com/aristocratos/btop) | Rich TUI, GPU/network/disk graphs |
| `du` | [ncdu](https://dev.yorhel.nl/ncdu) / [dust](https://github.com/bootandy/dust) | Interactive disk usage browsing |
| `df` | [duf](https://github.com/muesli/duf) | Colorful, filterable disk overview |
| `man` | [tldr](https://github.com/tldr-pages/tldr) | Practical examples, community-driven |
| `sed` | [sd](https://github.com/chmln/sd) | Simpler find-and-replace syntax |
| `curl` (APIs) | [httpie](https://github.com/httpie/cli) | JSON-aware, syntax-highlighted |
| `diff` | [delta](https://github.com/dandavison/delta) | Syntax-highlighted, side-by-side |
| Ctrl+R | [fzf](https://github.com/junegunn/fzf) | Fuzzy finder for files, history, everything |
| History | [atuin](https://github.com/atuinsh/atuin) | Synced, searchable shell history across machines |

Note: `exa` (the original `ls` replacement) is unmaintained since 2023. Use `eza` — it's the active community fork.

For a full setup guide on `zoxide`, see [Zoxide: The Smarter Way to Navigate Your Terminal](/zoxide).

### Installing a starter pack

<Tabs>
<Tab name="Ubuntu/Debian">
```bash
$ sudo apt install bat ripgrep fd-find eza btop ncdu fzf zoxide

# Fix name conflicts on Ubuntu:
$ sudo ln -s /usr/bin/batcat /usr/local/bin/bat
$ sudo ln -s /usr/bin/fdfind /usr/local/bin/fd
```
</Tab>
<Tab name="Fedora">
```bash
$ sudo dnf install bat ripgrep fd-find eza btop ncdu duf fzf zoxide
```
</Tab>
<Tab name="Arch">
```bash
$ sudo pacman -S bat ripgrep fd eza btop ncdu duf fzf zoxide
```
</Tab>
</Tabs>

<Notice type="success" title="Quick start on Ubuntu">
Install the essentials in one command:

```bash
sudo apt install bat ripgrep fd-find eza btop ncdu fzf zoxide
```

Then add to `~/.bashrc` for shell integration:
```bash
eval "$(zoxide init bash)"
eval "$(fzf --bash)"
alias ls='eza --icons'
alias cat='bat --paging=never'
```
</Notice>

Failure mode: On Ubuntu, `fd` is installed as `fdfind` and `bat` as `batcat` due to package name conflicts. Create symlinks as shown above.

---

## Quick reference cheat sheet

This condensed table covers every command in this guide. Bookmark it.

| Category | Command | Description | Example |
|----------|---------|-------------|---------|
| Navigation | `pwd` | Current directory | `pwd` |
| Navigation | `ls` | List contents | `ls -lah` |
| Navigation | `cd` | Change directory | `cd /var/log` |
| Files | `touch` | Create empty file | `touch new.txt` |
| Files | `cp` | Copy | `cp -r dir1/ dir2/` |
| Files | `mv` | Move/rename | `mv old new` |
| Files | `rm` | Remove | `rm -i file.txt` |
| Files | `ln` | Create link | `ln -s target link` |
| Archives | `tar` | Archive | `tar -czf a.tar.gz dir/` |
| Archives | `gzip` | Compress | `gzip file.txt` |
| Archives | `zip`/`unzip` | Zip archives | `zip -r a.zip dir/` |
| View | `cat` | Print file | `cat file.txt` |
| View | `less` | Paginated viewer | `less file.txt` |
| View | `head`/`tail` | First/last lines | `tail -f logfile` |
| Search | `grep` | Text search | `grep -rn "err" .` |
| Search | `find` | File search | `find . -name "*.log"` |
| Text | `sort` | Sort lines | `sort -n nums.txt` |
| Text | `uniq` | Deduplicate | `sort f \| uniq -c` |
| Text | `wc` | Count | `wc -l file.txt` |
| Text | `cut` | Extract columns | `cut -d: -f1 /etc/passwd` |
| Text | `awk` | Pattern processing | `awk '{print $1}' f` |
| Text | `sed` | Stream edit | `sed 's/old/new/g' f` |
| Text | `diff` | Compare files | `diff -u f1 f2` |
| Perms | `chmod` | Change permissions | `chmod 755 script.sh` |
| Perms | `chown` | Change ownership | `chown user:group f` |
| System | `uname` | System info | `uname -a` |
| System | `uptime` | Load averages | `uptime` |
| System | `free` | Memory usage | `free -h` |
| System | `df` | Disk space | `df -h` |
| System | `du` | Directory size | `du -sh /var/*` |
| System | `lsblk` | Block devices | `lsblk` |
| System | `dmesg` | Kernel messages | `dmesg \| tail` |
| Users | `whoami` | Current user | `whoami` |
| Users | `id` | User/group info | `id` |
| Users | `useradd` | Add user | `useradd -m newuser` |
| Users | `passwd` | Set password | `passwd newuser` |
| Users | `groups` | User's groups | `groups` |
| Users | `sudo` | Run as root | `sudo command` |
| Process | `ps` | Process snapshot | `ps aux` |
| Process | `top`/`htop` | Real-time viewer | `htop` |
| Process | `kill` | Terminate (SIGTERM) | `kill PID` |
| Process | `kill -9` | Force kill (SIGKILL) | `kill -9 PID` |
| Process | `pkill` | Kill by name | `pkill nginx` |
| Process | `nohup` | Survive logout | `nohup ./app &` |
| Process | `nice`/`renice` | Process priority | `nice -n 10 cmd` |
| Services | `systemctl` | Manage services | `systemctl status nginx` |
| Services | `journalctl` | View logs | `journalctl -u nginx -f` |
| Network | `ping` | Test connectivity | `ping -c4 host` |
| Network | `traceroute` | Trace path | `traceroute host` |
| Network | `dig` | DNS lookup | `dig domain.com` |
| Network | `nc` | Port test | `nc -zv host 22` |
| Network | `ip` | Network config | `ip a` |
| Network | `ss` | Socket stats | `ss -tuln` |
| Remote | `ssh` | Remote shell | `ssh user@host` |
| Remote | `ssh-keygen` | Generate key | `ssh-keygen -t ed25519` |
| Remote | `scp` | Secure copy | `scp f user@h:/path/` |
| Remote | `rsync` | Sync files | `rsync -avz src/ dest/` |
| Firewall | `ufw` | Ubuntu firewall | `ufw allow 443/tcp` |
| Firewall | `firewall-cmd` | RHEL firewall | `firewall-cmd --add-service=https` |
| Packages | `apt` | Debian/Ubuntu | `apt install pkg` |
| Packages | `dnf` | RHEL/Fedora | `dnf install pkg` |
| Packages | `pacman` | Arch | `pacman -S pkg` |
| Disk | `fdisk` | Partition | `fdisk /dev/sda` |
| Disk | `mkfs` | Create filesystem | `mkfs.ext4 /dev/sda1` |
| Disk | `mount`/`umount` | Mount/unmount | `mount /dev/sda1 /mnt` |
| Shell | `alias` | Command shortcut | `alias ll='ls -la'` |
| Shell | `history` | Command history | `history \| grep docker` |
| Shell | `tee` | Pipe + file | `cmd \| tee log.txt` |
| Shell | `xargs` | Build from stdin | `find . -name "*.tmp" \| xargs rm` |
| Shell | `watch` | Repeat command | `watch -n2 docker ps` |
| Shell | `export` | Set env var | `export KEY=value` |
| Shell | `source` | Reload config | `source ~/.bashrc` |
| Script | `echo` | Print text | `echo "hello"` |
| Script | `read` | Read input | `read -p "? " var` |
| Script | `cron` | Schedule tasks | `crontab -e` |
| Script | `at` | One-time schedule | `at 2:00 PM` |
| Dev | `git` | Version control | `git commit -m "msg"` |
| Dev | `docker` | Containers | `docker compose up -d` |
| Dev | `kubectl` | Kubernetes | `kubectl get pods` |
| Monitoring | `vmstat` | Virtual memory | `vmstat 1 5` |
| Monitoring | `iostat` | I/O stats | `iostat -x 1 3` |
| Monitoring | `sar` | System activity | `sar -u 1 3` |
| Misc | `wget` | Download file | `wget url` |
| Misc | `curl` | Transfer data | `curl -I url` |
| Misc | `file` | File type | `file mystery_file` |
| Misc | `stat` | File details | `stat file.txt` |
| Misc | `which` | Locate command | `which python3` |
| Misc | `lsof` | Open files | `lsof -i :80` |
| Misc | `env` | Environment vars | `env` |

---

## Frequently asked questions

<Accordion label="What are the most important Linux commands to learn first?" group="faq" expanded="true">
Start with these 12 commands — they cover 80% of daily terminal work:

`ls`, `cd`, `cp`, `mv`, `rm`, `cat`, `grep`, `find`, `chmod`, `sudo`, `ssh`, `tar`

Once you're comfortable, add `awk`, `sed`, `systemctl`, and `docker`. After that, the rest comes naturally as you need it.
</Accordion>

<Accordion label="What is the difference between apt and apt-get?" group="faq">
`apt` is the modern, user-friendly command for interactive terminal use — it has progress bars, color output, and a cleaner interface. `apt-get` is the older command designed for scripts and automation where output stability between versions matters. Use `apt` at the terminal, `apt-get` in Dockerfiles and CI scripts.
</Accordion>

<Accordion label="How do I find a file in Linux?" group="faq">
Use `find`: `find / -name "filename.txt" 2>/dev/null`

For faster name-based search: `find . -name "*.conf"`

If you have `locate` installed: `locate filename.txt` (uses a pre-built database, much faster but needs `updatedb` to refresh).
</Accordion>

<Accordion label="How do I check disk space in Linux?" group="faq">
```bash
df -h              # filesystem-level overview
du -sh /path       # directory size
du -sh /* | sort -h    # find biggest directories
```

When your VPS disk fills up, start with `df -h` to see which filesystem is full, then drill down with `du -sh`.
</Accordion>

<Accordion label="What is the difference between kill and kill -9?" group="faq">
`kill PID` sends SIGTERM (signal 15) — a polite request to shut down. The process can catch it, clean up, and exit gracefully.

`kill -9 PID` sends SIGKILL (signal 9) — an immediate, uncatchable termination. The process gets no chance to clean up temp files, close database connections, or release locks.

Always try `kill` first. Use `kill -9` only when the process ignores SIGTERM.
</Accordion>

<Accordion label="How do I check which ports are open?" group="faq">
```bash
ss -tuln           # listening TCP and UDP ports (modern, always available)
ss -tp             # established connections with process names
```

To test if a specific port is open on a remote host: `nc -zv host 443`

For a comprehensive port scan (use responsibly): `nmap host`
</Accordion>

<Accordion label="What are the best modern alternatives to classic Linux commands?" group="faq">
The most impactful swaps:
- `cat` → `bat` (syntax highlighting)
- `ls` → `eza` (colors, icons, tree)
- `grep` → `ripgrep` (faster, smarter)
- `find` → `fd` (simpler syntax)
- `top` → `btop` (rich TUI)
- `cd` → `zoxide` (remembers your directories)
- `Ctrl+R` → `fzf` (fuzzy search everything)

See the [Modern CLI Alternatives](#modern-cli-alternatives) section for install commands.
</Accordion>

---

## Conclusion

Mastering Linux commands is the single most valuable skill for anyone managing servers, self-hosting applications, or developing on Linux. This cheat sheet covers 100+ commands organized by task — from basic navigation to modern CLI tools.

<ListCheck>
<h5>Key takeaways</h5>
<ul>
<li>Learn the basics first: ls, cd, cp, mv, rm, cat, grep, find, chmod, sudo</li>
<li>Use modern alternatives where they help: ripgrep, fd, bat, eza, btop, fzf</li>
<li>Always verify after changes: ls -l after chmod, systemctl status after restart</li>
<li>Never rm -rf without thinking twice — there's no undo</li>
<li>Use sudo wisely — don't run everything as root</li>
<li>Practice on a real server — muscle memory beats memorization</li>
</ul>
</ListCheck>

The best way to learn is to use these commands on a real server. If you need one, [Hetzner](https://go.bitdoze.com/hetzner) has affordable Linux VPS starting at a few euros per month — perfect for practice.

Bookmark this cheat sheet and refer back to it as you build your Linux skills. For related deep-dives, check out [Docker commands](/docker-commands) and [Git commands](/git-commands).

For quick command references without reading full man pages, install `tldr` — it gives you practical examples instead of exhaustive documentation: `tldr tar` tells you the 5 things you actually need to know.