Command Line Fundamentals🔗
Part of Essentials
This is the first article in the Essentials series — the foundation every Linux professional must own cold. It assumes basic CLI familiarity (you've opened a terminal, run commands before, know what a path is).
If you've worked with Windows CMD or PowerShell, you already understand the concept: type a command, get output. What's different on Linux isn't the concept — it's that the shell is far more capable, and the productivity gap between someone who knows the shell's built-in tools and someone who doesn't is enormous.
This article closes that gap. The engineers who navigate Linux efficiently aren't faster typists — they've internalized about a dozen keyboard shortcuts and patterns that the shell gives you for free.
Anatomy of a Command🔗
Before you can get fast, you need to understand what you're actually typing. Most Linux commands follow this structure:
graph LR
A["⚙️ COMMAND\nls"] --> D["📤 Output"]
B["🔧 OPTIONS\n-l -h"] --> D
C["📁 ARGUMENT\n/var/log"] --> D
style A fill:#2d3748,stroke:#d69e2e,stroke-width:2px,color:#fff
style B fill:#2d3748,stroke:#68d391,stroke-width:2px,color:#fff
style C fill:#2d3748,stroke:#63b3ed,stroke-width:2px,color:#fff
style D fill:#1a202c,stroke:#cbd5e0,stroke-width:2px,color:#fff
ls -lh /var/log
# ^ ^^ ^^^^^^^
# | | argument: the directory to list
# | options: -l (long format) + -h (human-readable sizes)
# command: list directory contents
Short Options vs Long Options🔗
Most commands offer two forms for every option: a compact single-character form (prefixed with -) and a descriptive word form (prefixed with --). They do the same thing.
ls -l # (1)!
ls --format=long # (2)!
grep -r 'error' /var/log # (3)!
grep --recursive 'error' /var/log # (4)!
- Short form.
- Long form — same result.
- Short form.
- Long form — same result.
Short options can be combined. Long options cannot.
- Works, but verbose.
- Same thing — combined short options.
When to use which:
- Short options in commands you type interactively — faster
- Long options in scripts — self-documenting, much easier to read months later
Arguments: What the Command Acts On🔗
Arguments are the targets: files, directories, patterns, or other input. Some commands require them; most accept them.
- Lists the current directory — no argument means default.
- Lists
/etc— an explicit argument. - Multiple arguments — lists both.
Order Matters
Options typically come before arguments. Some commands are strict about this. When in doubt, follow the pattern command [options] [arguments].
Where You've Seen This🔗
If you've used PowerShell, you already know tab completion. If you've used Docker CLI, kubectl, git, or the Python REPL, you've used tab completion there too — because it's built into the terminal and Bash, not the individual tools. Everything in this article applies across all of them.
The history shortcuts (Ctrl+R, !!, !$) are Linux/macOS-specific patterns, but the concept — not retyping commands you've already run — is universal. PowerShell has PSReadLine for the same purpose. What Linux engineers have is a richer, keyboard-driven version that's been stable for decades.
Command chaining (&&, ||, ;) maps directly to what you'd write in a batch file or PowerShell script with -and, -or, and sequencing. The Linux version is more concise and more composable.
The Shell's Productivity Superpowers🔗
This is where the real gap between beginners and professionals lives. These features are built into Bash and work on any Linux system — no installation required.
-
Tab Completion
Why it matters: Tab completion is the single biggest speed multiplier at the command line. It prevents typos, completes paths you can't remember, and shows you available options.
Tab Completion in Actionls /var/log/ng<TAB> # expands to: ls /var/log/nginx/ systemctl restart post<TAB> # expands to: systemctl restart postgresqlKey insight: If nothing happens when you press Tab, it means there's more than one match. Press Tab twice to see all completions.
-
History Search (Ctrl+R)
Why it matters: Every engineer runs long, complex commands.
Ctrl+Rlets you find any command you've run before in seconds — without scrolling through history line by line.Reverse History Search# Press Ctrl+R, then start typing (reverse-i-search)`docker': docker compose up -d --build # Press Ctrl+R again to cycle through older matches # Press Enter to run, or Right arrow to edit firstKey insight: Type just a few unique characters from the command you're looking for.
k8s,prod,deploy— whatever's distinctive. -
History Expansion
Why it matters: Often you want to re-run the last command slightly modified, or pass the last argument to a new command. History expansion does this in 2-3 keystrokes.
History Expansion Shortcutscat /etc/nginx/nginx.conf sudo !! # (1)! # → sudo cat /etc/nginx/nginx.conf mkdir /opt/myapp/config cd !$ # (2)! # → cd /opt/myapp/config diff /etc/hosts /etc/hosts.bak cp !^ # (3)! # → cp /etc/hosts!!repeats the entire last command — here, re-running it withsudoprepended.!$is the last argument of the previous command.!^is the first argument of the previous command.
Key insight:
sudo !!is one of the most useful patterns in Linux — you run a command, realize you neededsudo, and just prepend it. -
Cursor Shortcuts
Why it matters: You've typed a long command and need to fix something in the middle. These shortcuts let you navigate and edit without reaching for the mouse.
Cursor ShortcutsCtrl+A # (1)! Ctrl+E # (2)! Alt+B # (3)! Alt+F # (4)! Ctrl+W # (5)! Ctrl+K # (6)! Ctrl+U # (7)! Ctrl+L # (8)!- Jump to the beginning of the line.
- Jump to the end of the line.
- Jump back one word.
- Jump forward one word.
- Delete the word before the cursor.
- Delete from the cursor to the end of the line.
- Delete the entire line.
- Clear the screen (same as
clear).
Key insight:
Ctrl+Wis especially useful — it deletes the last word, letting you fix a path or argument without retyping the whole command.
Navigating History Without Ctrl+R🔗
History search covers most cases, but knowing the other ways to work with history rounds out your toolkit.
↑ # (1)!
↓ # (2)!
history # (3)!
# 1001 ls -lh /var/log
# 1002 cat /etc/nginx/nginx.conf
# 1003 sudo systemctl restart nginx
# 1004 history
!1003 # (4)!
# → sudo systemctl restart nginx
history | grep docker # (5)!
# 987 docker ps
# 991 docker logs myapp
# 995 docker compose up -d
- Previous command — the arrow keys scroll through history one command at a time.
- Next command.
- View your full command history.
- Re-run a specific command from history by its number.
- Search history for matching commands.
Persist History Across Sessions
By default, Bash only keeps a limited history and loses it between terminal sessions. Add these to your ~/.bashrc to fix that:
export HISTSIZE=10000 # (1)!
export HISTFILESIZE=20000 # (2)!
export HISTCONTROL=ignoredups:erasedups # (3)!
shopt -s histappend # (4)!
- Keep 10,000 commands in memory.
- Keep 20,000 commands on disk.
- No duplicate entries.
- Append instead of overwriting.
After editing, run source ~/.bashrc to apply.
Command Chaining🔗
Running commands one at a time is fine. Chaining them together is what you'll see in every real-world script and shell session.
Exit Codes: The Glue of Chaining🔗
Every command exits with a numeric status code. 0 means success. Anything else means failure.
ls /etc/nginx
echo $?
# 0 → success, directory exists
ls /etc/doesnotexist
echo $?
# 2 → failure, directory not found
You don't usually check $? directly in interactive sessions — but it's what the chaining operators use behind the scenes.
The Three Chaining Operators🔗
Runs the second command regardless of whether the first succeeded.
- Runs
apt upgradeeven ifapt updatefails.
Use when the second command doesn't depend on the first.
Runs the second command only if the first succeeded (exit code 0).
- Only
cdifmkdirsucceeded — protects you from cd-ing into a directory that doesn't exist. - Only deploy if the pull succeeded.
This is the pattern you'll see most in production scripts. It's defensive — if something fails early, the rest doesn't run.
Combining Chains🔗
These operators compose naturally:
mkdir /opt/myproject && cd /opt/myproject && git init # (1)!
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak && vim /etc/nginx/nginx.conf # (2)!
- Create a directory, move into it, and initialize a git repo —
&&stops the chain if any step fails. - Back up a config file, then edit it — the edit only runs if the backup succeeded.
Chain or Script?
If you find yourself writing the same chain more than twice, turn it into a shell script. But start with chains — they're fast to prototype and easy to reason about.
Common Scenarios🔗
Use tab completion to explore.
You know the file is somewhere in /var/log but you can't remember the exact path.
ls /var/log/<TAB><TAB>
# Shows everything in /var/log/
ls /var/log/nginx/<TAB><TAB>
# access.log error.log
tail -f /var/log/nginx/access.log
Pattern: Tab twice to see options, type a few characters to narrow down, Tab to complete.
Use Ctrl+R to find it.
You ran a complex find command last week and want to run it again.
# Press Ctrl+R
(reverse-i-search)`find': find /var/log -name "*.log" -mtime -7 -size +10M
# Press Enter to run immediately
# Press Right arrow to edit before running
Pattern: Press Ctrl+R, type something distinctive from the command (like the directory or a flag), hit Enter.
Use !! to avoid retyping.
cat /etc/sudoers
# cat: /etc/sudoers: Permission denied
sudo !!
# → sudo cat /etc/sudoers
Pattern: sudo !! is muscle memory for experienced engineers.
Use cursor shortcuts to fix it without retyping.
You typed a long command but the path at the beginning is wrong.
- You typed
/var/lgo/by mistake.Ctrl+Ajumps to the start of the line,Alt+Fskips forward word by word, andCtrl+Wdeletes/var/lgo/so you can retype/var/log/.
Pattern: Ctrl+A to jump to start, Alt+F to hop over words, Ctrl+W to delete and retype the bad part.
Quick Reference🔗
Keyboard Shortcuts🔗
| Shortcut | What It Does |
|---|---|
Tab |
Complete command, path, or filename |
Tab Tab |
Show all possible completions |
↑ / ↓ |
Scroll through history |
Ctrl+R |
Reverse search through history |
Ctrl+A |
Jump to beginning of line |
Ctrl+E |
Jump to end of line |
Alt+B |
Jump back one word |
Alt+F |
Jump forward one word |
Ctrl+W |
Delete word before cursor |
Ctrl+K |
Delete from cursor to end of line |
Ctrl+U |
Delete entire line |
Ctrl+L |
Clear the screen |
Ctrl+C |
Cancel current command |
Ctrl+D |
Exit the shell (or send EOF) |
History Expansion🔗
| Shortcut | What It Does |
|---|---|
!! |
Entire last command |
!$ |
Last argument of previous command |
!^ |
First argument of previous command |
!1003 |
Run command #1003 from history |
history \| grep X |
Search history for X |
Chaining Operators🔗
| Operator | Behavior |
|---|---|
; |
Run second command regardless |
&& |
Run second command only if first succeeded |
\|\| |
Run second command only if first failed |
Practice Exercises🔗
Exercise 1: Tab Completion Practice
Without using your arrow keys or retyping, navigate to /var/log/ and list the contents using only Tab completion.
Then try: complete systemctl stat<TAB> — what does it expand to?
Exercise 2: History Recall
Run this command:
Now, without retyping it, use Ctrl+R to find and run it again. Then use !$ to cd into the same directory.
Exercise 3: Chaining Practice
Write a single chained command that:
- Creates a directory
/tmp/testproject - Only if that succeeded, creates a file inside it called
README.md - Only if that succeeded, prints "Setup complete"
Exercise 4: The sudo !! Pattern
Run the following command and get a permission denied error:
Then, without retyping the command, run it with sudo.
Quick Recap🔗
The command line fundamentals every Linux professional owns cold:
- Command anatomy:
COMMAND [OPTIONS] [ARGUMENTS]— short options combine (-lht), long options self-document (--human-readable) - Tab completion: your #1 speed tool — one Tab to complete, two Tabs to see all options
- Ctrl+R: find any previous command by typing a few characters
- History expansion:
sudo !!(repeat last command),cd !$(last argument),!1003(by number) - Cursor shortcuts:
Ctrl+A/Eto navigate,Ctrl+Wto delete a word,Ctrl+Lto clear - Chaining:
;(always),&&(on success),||(on failure) — the backbone of shell automation
Further Reading🔗
Command References🔗
man bash— the complete Bash reference manual (long, but comprehensive)man history— the history command in detailbash --version— which version of Bash you're running
Deep Dives🔗
- Bash Guide for Beginners — The Linux Documentation Project's thorough Bash guide
- The Art of Command Line — battle-tested command line tips from experienced engineers
- Bash Hackers Wiki — detailed reference for shell scripting and interactive Bash
Official Documentation🔗
- GNU Bash Manual — the authoritative Bash reference
- Red Hat Bash Reference — RHEL-specific shell configuration guide
What's Next?🔗
You've got the fundamentals. Now you need to actually navigate the Linux filesystem — and that means understanding where everything lives.
Head to Filesystem Hierarchy to learn the structure every Linux system shares, why /etc is for configuration, why /var is for variable data, and where to look for logs, binaries, and application files.
Once you understand the layout, Finding Files will show you how to locate anything on a system quickly — whether it's a config file, a log, or a binary you're not sure where was installed.