SONUB home EN English 한국어 日本語 中文 हिन्दी বাংলা اردو Español Português Français Deutsch Русский العربية Bahasa Indonesia Tiếng Việt ไทย Türkçe

How to enable notifications

Notifications are unavailable in this browser or on this address. Try a supported browser on the secure SONUB site.

If notifications are blocked, allow them in your browser settings.

  1. Open the site controls beside the address bar, or your browser’s site settings. Set Notifications for this site to Allow.
  2. In your device settings, allow notifications for your browser and check Do Not Disturb or Focus.
  3. Return to SONUB, reload the page, and use the bell to enable notifications.

On iPhone or iPad, add SONUB to your Home Screen, open it there, then allow notifications.

Before Python, start with shell basics

often comes to mind when learning , but and are the practical foundation for installing and running AI tools.

Shell is not the main language for building AI , but it predates Python and has long helped people manage files and automate everyday tasks.

No deep study needed: start with a few common commands and build skills you can use for a lifetime.

The language behind every tool

Shell programmingthe language that puts AI to work

The is useful for running , managing files, and automating development. can also run through , apps, notebooks, and . A is one useful interface, not a requirement for every AI user.

View curriculum
  • Practice instantly — no install
  • macOS · compatible
  • Safe
MY LEARNING JOURNEY Take your first step today
0 / 13 lessons complete 0%
13step roadmap
34practice missions
0commands run
STEP BY STEP

Master shell in 13 guided lessons

Learn the basics, then , , running other languages and — all the way to automation.

Beginner → Practical
Part 1 · LESSON 1–LESSON 4

Command basics

Open the , handle files, find and count text, and chain together. After these four lessons you can already use a terminal on your own.

  1. LESSON 01 Complete NEXT Meet the terminal Command syntax and finding your location 3 missions Start
  2. LESSON 02 Complete NEXT Files and folders Create, move, delete, and inspect content 3 missions Start
  3. LESSON 03 Complete NEXT Text-processing toolkit Find with grep; count with sort, uniq, and wc 2 missions Start
  4. LESSON 04 Complete NEXT Pipes and redirection Connect commands and send output to files 2 missions Start
Part 2 · LESSON 5–LESSON 9

Writing scripts

Store values (), decide and repeat (conditions and ), and give a bundle of a name () to build your own automation — safely.

  1. LESSON 05 Complete NEXT Variables and expansion Store values, reuse them, and calculate 2 missions Start
  2. LESSON 06 Complete NEXT Conditions and loops Decide with if and repeat with for 2 missions Start
  3. LESSON 07 Complete NEXT Functions and scripts Create your own commands 1 missions Start
  4. LESSON 08 Complete NEXT Practical scripting Build useful automation 1 missions Start
  5. LESSON 09 Complete NEXT Safe shell: quotes and traps Finish with defensive scripting habits 2 missions Start
Part 3 · LESSON 10–LESSON 13

Real-world tools

Install and , then put , , and to work from the .

  1. LESSON 10 Complete NEXT Node.js commands Run JavaScript with node, npm, and npx 3 missions Start
  2. LESSON 11 Complete NEXT Install developer tools Put Grok, Codex, Claude Code, and Firebase on your PATH 3 missions Start
  3. LESSON 12 Complete NEXT Run other languages from the shell Drive Python, awk, and sed straight from the terminal 5 missions Start
  4. LESSON 13 Complete NEXT Regular expressions Find, pick and change text by its "shape" 5 missions Start
WHY SHELL?

Learn it once. Use it everywhere.

Run AI-generated solutions yourself

When you ask to organize files or automate a task, it often responds with a . Reading lets you verify that answer before you run it.

A foundation that works everywhere

Shell has been a stable, universal computer language for decades. Learn it once and use it across macOS, , , platforms, and AI tools.

macOS users can follow along as-is

macOS uses by default, but nearly every and concept in this course works the same way. A shebang runs a script with Bash explicitly, and apart from a few advanced differences such as index numbering it all carries over.

HANDS-ON EXAMPLE

Build a web server in one shell script

In about 20 lines of you can run a real web that returns a page to the — a vivid reminder that is just "a promise to exchange one chunk of text."

server.sh
#!/bin/bash

PORT=8084
PIPE=simple-web-server-pipe

rm -f "$PIPE"
mkfifo "$PIPE"

response() {
    read -r method path _
    echo "[$(date)] $method $path" >&2
    index=$(cat index.html)
    printf 'HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\n\r\n%s' \
      "$index"
}

while true; do
    response < "$PIPE" | nc -l "$PORT" > "$PIPE"
done
  1. mkfifo "$PIPE" Creates a . The request receives and the response we build both travel through this channel.
  2. nc -l "$PORT" nc (netcat) opens 8084 and waits for the browser to connect — a server in a single .
  3. response() Reads the request line (method and ), logs it, and returns index.html as an HTTP 200 response.
  4. while true; do … done After responding, the connection closes and the starts over to accept the next visitor, keeping the server alive.

Put an index.html in the same folder, run bash server.sh, then open :8084 in your browser. Not for production, but perfect for understanding how HTTP works.

LESSON 01 · HANDS-ON LAB

Meet the terminal

Learn how to enter , understand the , and find your current location.

In plain words Your first chat with the computer in text: you type one line, it answers with one line.

4 learning goals 3 practice missions About 10 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 02 · HANDS-ON LAB

Files and folders

Practice creating, copying, moving, deleting, and reading files and folders.

In plain words What you do with a mouse in a file manager (make, copy, move, delete), done by typing.

4 learning goals 3 practice missions About 10 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 03 · HANDS-ON LAB

Text-processing toolkit

Find matching lines, and deduplicate text, and count lines or words.

In plain words A highlighter, a sorter and a counter for a very long text.

4 learning goals 2 practice missions About 10 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 04 · HANDS-ON LAB

Pipes and redirection

Connect output with | and results into files with > and >>.

In plain words Like a conveyor belt: each command's result moves to the next, then into a box (a file).

4 learning goals 2 practice missions About 15 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 05 · HANDS-ON LAB

Variables and expansion

Store reusable values and insert , results, and calculations into text.

In plain words Like a labelled box: put a value in, then take it out later by its name.

4 learning goals 2 practice missions About 10 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 06 · HANDS-ON LAB

Conditions and loops

Use if to choose behavior and for or while to repeat work.

In plain words Like 'if it rains, take an umbrella' and 'climb ten steps': deciding and repeating.

4 learning goals 2 practice missions About 15 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 07 · HANDS-ON LAB

Functions and scripts

Bundle reusable into , pass , and understand and .

In plain words Like a recipe card for a job you do often: say its name and the whole job is done.

4 learning goals 1 practice missions About 15 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 08 · HANDS-ON LAB

Practical scripting

Combine everything you learned into safer that validate inputs and automate real work.

In plain words Like dominoes: the next step falls only if the one before it succeeded.

4 learning goals 1 practice missions About 15 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 09 · HANDS-ON LAB

Safe shell: quotes and traps

Avoid and mistakes, and write defensive that stop safely on errors.

In plain words Like fastening a seat belt: and safety stop accidents before they happen.

4 learning goals 2 practice missions About 15 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 10 · HANDS-ON LAB

Node.js commands

Learn to use from the : check versions, run , manage with , and run one-off tools with .

In plain words Like an app store for : npm fetches tools, and runs .

4 learning goals 3 practice missions About 10 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 11 · HANDS-ON LAB

Install developer tools

A short guide to installing and CLIs in the . With Node and ready, most tools start with one .

In plain words Like moving tools into a new workshop and checking each one works.

4 learning goals 3 practice missions About 10 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 12 · HANDS-ON LAB

Run other languages from the shell

The does not do everything itself — it conducts other languages. Learn one-line execution with -c, for multi-line , and the two tools reaches for most: and .

In plain words Like an interpreter: the shell hands work to , awk or sed and brings back the result.

6 learning goals 5 practice missions About 30 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
LESSON 13 · HANDS-ON LAB

Regular expressions

A (regex) is a small language for writing down the shape of the text you want. Dates, emails and all have different values but the same shape: find them with , change them with , and check them in and . You also learn the that come built in on macOS, and Windows.

In plain words Like a stamp of a shape such as 'three digits, a dash, four digits' that finds every match.

6 learning goals 5 practice missions About 30 min
Start practicing Lyen, the AI tutor, answers in text and voice (sign-in needed).
  1. 1 Read one concept at a time
  2. 2 Press the example right below it, then Enter
  3. 3 Solve the missions in the terminal
  4. 4 Stuck? Ask AI
LEARNING GOALS

What you will accomplish

  1. 1

    Use the basic command [] [] structure

  2. 2

    Check your location and move between folders

  3. 3

    Print text with

  4. 4

    Find help with man and --help

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its command into the practice 's input line, then press Enter to run it. You can edit it first.

01

Terminal and prompt

A is a text window for giving instructions to a computer. The $ or % means the is ready; type one and press Enter. The shell (here, ) is the inside the window that reads and runs your command, and working with a computer by typing commands like this is called a (command-line interface).

02

The three parts of a command

Most contain an action, , and a . For example, -l notes.txt means list files, show details, and use the notes.txt file. For a command you do not know, man followed by its name or the command with --help shows its manual (the practice shows only a short summary).

03

Know where you are

Your always matters. Use to see it, to move, and to inspect its contents. ~ means your and .. means the .

04

Opening a terminal on your own computer

On this page you can practise right away in the practice , with nothing to install. On a Mac, open the Terminal app (search for Terminal in Spotlight). On Windows, open from the Start menu; to use the same as this course, install and open Ubuntu. On most desktops, press Ctrl+Alt+T.

WATCH OUT

Common beginner mistakes

  • and need spaces: use -la, not ls-la.
  • is . Use ls and , not LS or Cd.
LEARNING GOALS

What you will accomplish

  1. 1

    Create folders and empty files

  2. 2

    Copy, move, rename, and delete files

  3. 3

    Read files with , , and

  4. 4

    Use destructive safely

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its command into the practice 's input line, then press Enter to run it. You can edit it first.

01

Create — mkdir and touch

creates folders and creates empty files. mkdir -p a/b/c conveniently creates every missing . Like most , they print nothing when they succeed, so run to see the result.

02

Copy, move, rename — cp and mv

keeps the original and makes a copy. moves an item, and mv old new also renames it.

03

Read content — cat, head, tail

prints a whole file, while and show only the beginning or end. deletes immediately without using the Trash, so use it carefully.

WATCH OUT

Common beginner mistakes

  • -rf removes a whole folder without confirmation. Always inspect the first.
  • and can an existing target silently. Build the habit of using -i.
LEARNING GOALS

What you will accomplish

  1. 1

    Find matching lines with

  2. 2

    Use grep -i and -n

  3. 3

    Sort lines with sort

  4. 4

    Count with

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its into the practice 's input line, then press Enter to run it. You can edit it first.

01

grep — find text

word file prints only matching lines. Add -i for search, -n for line numbers, or -r for folder search.

02

Sort and count — sort, uniq, wc

orders lines, combines adjacent duplicates, and -l counts lines. Together they make quick statistics.

WATCH OUT

Common beginner mistakes

  • is . and shell are different words, so grep shell will not find a line that says Shell. Add -i, as in grep -i shell, to ignore case.
  • grep prints nothing when there is no match. Use grep -q when you only need a yes/no result.
LEARNING GOALS

What you will accomplish

  1. 1

    Connect commands with |

  2. 2

    Save output with >

  3. 3

    Append output with >>

  4. 4

    Understand standard-output flow

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its command into the practice 's input line, then press Enter to run it. You can edit it first.

01

Pipes ( | )

commandA | commandB sends A’s output directly into B. Small tools combine into powerful one-line workflows.

02

Redirection ( >, >>, < )

> a file, >> , and < uses a file as input. Use 2> to redirect errors separately.

03

Show and save at once — tee

Insert in the middle of a to pass the on to the screen (or the next ) while also saving it to a file. The name comes from a T-shaped pipe fitting. Unlike > (which hides output by diverting it into a file), command | tee file both shows and saves it. Use tee -a to instead of — handy for keeping a log while still watching the result.

WATCH OUT

Common beginner mistakes

  • > immediately replaces the file. Use >> when existing content must remain.
  • Do not mix up | and >. > does not search anything — it just saves the list into a new file named grep. Use | to hand output to another and > to save it to a file.
LEARNING GOALS

What you will accomplish

  1. 1

    Create and read variables

  2. 2

    Quote variables safely

  3. 3

    Calculate with $(( ))

  4. 4

    Capture command output with $( )

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its command into the practice 's input line, then press Enter to run it. You can edit it first.

01

Create and read variables

Create a with name=value and read it with $name. Never put spaces around =: name=Lyen works, while name = Lyen does not.

02

Protect values with double quotes

Use "$name" so values containing spaces stay together. This is one of the most important safe- habits.

03

Arithmetic and command substitution

$(( 3 + 4 )) returns 7. $() captures a command result so you can store it in a or insert it into text.

WATCH OUT

Common beginner mistakes

  • Spaces around = make the treat the name as a . Use foo=bar.
  • split at spaces. Make "$name" your default.
LEARNING GOALS

What you will accomplish

  1. 1

    with if / elif / else

  2. 2

    Compare , numbers, and files with

  3. 3

    Process lists with for

  4. 4

    Distinguish numeric and string comparisons

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its into the practice 's input line, then press Enter to run it. You can edit it first.

01

The if statement

In if ; then ... fi, the inner run only when the condition is true. Add elif and else for more , and always close with fi.

02

Comparisons with [[ ]]

Use == and != for ; for numbers use -eq (equal), -gt (greater than), -lt (less than), -ge (greater than or equal) and -le (less than or equal); and use -f or -d to check files and folders.

03

The for loop

for item in list; do ... done puts each list item into a . You can over {1..5} or over files.

04

Repeat a fixed number of times with seq

To repeat a set number of times (like 1 to 20), use to build the numbers and pass them to for: for i in $(seq 1 20); do ... done, where $(seq 1 20) expands to 1 2 3 … 20. Do not drop the in — writing for i $(seq 1 20) is an error, so always keep the "for in list" order. You can write the same with a brace: for i in {1..20}.

WATCH OUT

Common beginner mistakes

  • In [[ $x > 7 ]], > compares text, not numbers. Use -gt for numeric comparison.
  • Spaces are required inside [[ and ]].
LEARNING GOALS

What you will accomplish

  1. 1

    Define and call a function

  2. 2

    Use function arguments such as $1

  3. 3

    Explain #!/bin/bash

  4. 4

    Understand

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its command into the practice 's input line, then press Enter to run it. You can edit it first.

01

Define and call functions

name() { ; } turns a command sequence into a reusable name. Inside a , $1 and $2 hold incoming .

02

Script files and shebangs

Save in a .sh file to run them again. tells the system to execute that file with , including on a macOS zsh setup.

03

Permission and arguments

Run +x hello.sh before ./hello.sh. Read incoming values with $1, $2, $@, and $#.

WATCH OUT

Common beginner mistakes

  • Without +x, ./hello.sh may fail with . You can also run hello.sh.
  • Quote such as "$1" so spaces stay intact.
LEARNING GOALS

What you will accomplish

  1. 1

    Read success or failure through

  2. 2

    Chain success and failure with

  3. 3

    Process many files with for

  4. 4

    Understand scheduled execution with

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its into the practice 's input line, then press Enter to run it. You can edit it first.

01

Exit codes and $?

Every returns 0 for success or another number for failure. reads the previous result, and A B runs B only when A succeeds.

02

Automate repeated work

Combine with file to process many items, such as copying every photo into a dated backup folder.

03

Scheduled runs — cron

runs at fixed times. Its five time are minute, hour, day, month, and weekday; 0 3 * * * means every day at 3 a.m.

WATCH OUT

Common beginner mistakes

  • If a critical fails, stop with command exit 1 instead of continuing with bad state.
  • Quote and use absolute paths in , where the working folder may differ.
LEARNING GOALS

What you will accomplish

  1. 1

    Explain double, single, and unquoted text

  2. 2

    Understand word splitting and globbing

  3. 3

    Use set -euo pipefail

  4. 4

    Always quote

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its into the practice 's input line, then press Enter to run it. You can edit it first.

01

Three kinds of quoting

"$var" expands the but preserves spaces; '$var' keeps everything ; unquoted $var may split at spaces and expand characters.

02

Word splitting and globbing

values split into multiple and * or ? can turn into filenames. A single filename containing spaces can then be mistaken for two.

03

Defensive options

set -euo pipefail stops on errors, rejects undefined , and catches failures inside . can find many problems before execution.

WATCH OUT

Common beginner mistakes

  • Most accidents begin with missing . Make “always quote ” a habit.
  • Use [[ $a = b $c = d ]] instead of mixing operators inside single brackets.
LEARNING GOALS

What you will accomplish

  1. 1

    Check the Node.js version with node -v

  2. 2

    Run a JavaScript file with node app.js

  3. 3

    Install packages and run scripts with npm

  4. 4

    Run a tool once with npx without a

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its into the practice terminal's input line, then press Enter to run it. You can edit it first.

01

What is Node.js?

runs outside the — in terminals and . Web apps, tools, build , and many depend on it. After basics, Node is the next foundation for installing .

02

The node command

Use -v (or --version) to check the version. node app.js runs a file; node -e "console.log(1+1)" runs a one-liner. Missing files or errors print an error message.

03

npm and package.json

installs and manages . lists name, version, , and dependencies. npm install fetches dependencies; npm run start runs a script. runs a package once without a permanent .

WATCH OUT

Common beginner mistakes

  • If or says " not found", is not installed yet. Install from nodejs.org or , then reopen the .
  • npm install -g often causes permission and security issues. Prefer nvm or fix global npm permissions and install without sudo.
LEARNING GOALS

What you will accomplish

  1. 1

    Explain why is a prerequisite for many tools

  2. 2

    Know the common install commands for Claude Code, Codex, Grok, and

  3. 3

    Tell (-g) apart from one-off runs ()

  4. 4

    Verify installs with version commands

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its command into the practice terminal's input line, then press Enter to run it. You can edit it first.

01

Why install tools in the terminal?

Modern development is not only an editor. (Grok Build, OpenAI Codex, Claude Code), CLIs (Firebase tools), and managers run in the . Lesson 10 Node and skills are the starting point.

02

Common installs (short summary)

Official methods can change — always prefer the vendor docs. Typical starts: Claude via -fsSL ://claude.ai/install.sh | (or install -g @anthropic-/claude-code). OpenAI Codex via curl -fsSL https://chatgpt.com/codex/install.sh | sh (or npm install -g @openai/codex). Grok via the official installer or npm install -g @xai-official/grok. : npm install -g firebase-tools. Then verify with claude --version, codex --version, firebase --version.

03

Safe install habits

Prefer reading | from trusted official domains. If global hits permission errors, fix instead of using . In teams and , pin tools as so versions stay consistent.

WATCH OUT

Common beginner mistakes

  • | is convenient but risky from unknown sources. Confirm the official first.
  • Similar tool names use different . Use exact names like @anthropic-/claude-, @openai/codex, and .
LEARNING GOALS

What you will accomplish

  1. 1

    Run one-liners in other languages with -c and -e

  2. 2

    Save a program to a file and run it with python3 file.py

  3. 3

    Pass a multi-line program to a with a heredoc (<<PY)

  4. 4

    Edit text across a file with sed

  5. 5

    Pick out and total them with awk

  6. 6

    Check AI-generated before you run it

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its command into the practice 's input line, then press Enter to run it. You can edit it first.

01

The shell is the conductor, not the soloist

Doing every calculation in alone hits a wall fast. Instead the shell decides who to call and when: for math and data, for tables, for bulk text edits — and the shell stitches the results together. Knowing the shell means you can use languages you have never studied.

02

Pass a single line — -c and -e

Most languages accept as an and run it immediately: -c "code", -e "code", -e, ruby -e. Just replacing your calculator with python3 -c "print(2**10)" makes the far more powerful.

03

Save it to a file and run it

If a is worth keeping, put it in a file. Write the into hello.py and hello.py runs it as is. Add the you met in Lesson 7 as the first line — #!/usr/bin/env python3 — then +x hello.py, and ./hello.py runs on its own without python3 in front. Type afterwards and you see whether it succeeded (0) or failed (1), so you can chain the next with exactly as Lesson 8 showed.

04

Pass many lines — the heredoc

For a longer than one line, -c gets awkward. That is what a is for. Write - <<'PY' and everything from the next line until a line reading PY is handed to on . The lone - means "read the from standard input instead of a file." This is the form coding often use when they edit your files.

05

<<'PY' is not the same as <<PY

Quote the (<<'PY') and the body is passed through . Leave it unquoted (<<PY) and the first substitutes $variables and $() inside it. rarely contains $, but a or that does will break silently — so quoting the tag is the default when passing code.

06

sed — the stream editor that finds and replaces

's/find/replace/' changes the first match on each line; add g (s/…/…/g) to change every match on the line. Put a line number or // in front to choose which lines (2s/…/…/, /error/s/…/…/), and pair -n with p to print only the lines you picked. The need not be / — for , s|/old/path|/new/path| reads much better. To edit the file itself, sed -i.bak 's/find/replace/' file is the safe form: it keeps the original as file.bak. (macOS and differ here — see Watch out below.)

07

awk — a small programming language for tables

is not a ; it is a language. It splits each line on whitespace into $1, $2, $3, with NF as the count and NR as the line number. The shape is awk 'pattern { action }': omit the pattern for every line, omit the action to print the whole line. A BEGIN{} at the front and END{} at the back handle setup and wrap-up, so totals, averages, and per-key tallies fit in one line.

08

Chain languages with pipes

written to read and write standard output chain freely through . sales.txt | '{print $2}' | -n | -3 means "read the file, take the second , sort numerically, keep the three largest" — all in one line. awk and are joined this way; takes its through -c or a instead. That is what it means for the to be the conductor.

09

Run AI-generated code safely

usually answers in exactly this form. Before pasting it, check three things: read the file it touches, look for or > that , and back up anything important first with original original.bak. Being able to read means being able to verify what the AI gave you.

WATCH OUT

Common beginner mistakes

  • Always wrap an in . With double quotes the treats $1 as its own and replaces it with nothing: awk '{print $1}' works, awk "{print $1}" does not.
  • The of a heredoc must sit at the very start of the line, with no spaces, spelled exactly the same. If you need indentation, use <<- and indent with tabs.
  • Quote the tag (<<'PY') when passing . Unquoted, any $ inside your code becomes a shell variable and breaks it silently.
  • -i rewrites the file with no undo. Run it without -i first, check the result on screen, then add it.
  • On macOS, sed -i 's/…/…/' file without a backup name fails with an undefined label error and leaves the file untouched — macOS sed requires a name after -i. Write it as sed -i.bak and the same works on macOS and alike.
  • sed 's/a/b/' file > file empties the file before reading it, so the contents are lost. Write to a different name.
LEARNING GOALS

What you will accomplish

  1. 1

    Describe the shape of text with basic symbols such as . * + ? [ ] ^ $

  2. 2

    Find matching lines with grep -E and pull out only the matching part with -o

  3. 3

    Reorder and fix text with sed -E and ( )

  4. 4

    Explain basic versus , and why \d is not a digit in grep -E

  5. 5

    Check values with [[ value =~ pattern ]] in shell scripts and with Python's re module

  6. 6

    Choose the regex commands that come built in on macOS, Linux and Windows

CORE CONCEPTS

Learn the core ideas

TRY IT Press an example to put its command into the practice 's input line, then press Enter to run it. You can edit it first.

01

A regular expression describes the "shape" of text

Say you want every phone number in a document. Searching for 010-1234-5678 finds only that one number. But every phone number has a shape: "3 digits, a dash, 4 digits, a dash, 4 digits". A lets you write that shape with symbols, like [0-9]{3}-[0-9]{4}-[0-9]{4}. Learn it once and you use almost the same symbols in , , , vim, , and PHP.

02

Symbols that pick one character

. is any one character (a.c matches abc and a1c). [abc] is one of the characters in the brackets, [^abc] is one character that is not in them, and [a-z] or [0-9] is one character in a range. Common sets have short names: \d is a digit, \w is a word character (letter, digit or _), and \s is whitespace. Capital letters (\D \W \S) mean the opposite. tools also accept names such as [[:digit:]] and [[:space:]].

03

Symbols that say how many times

* means the character just before it 0 or more times, + means 1 or more, ? means 0 or 1 (colou?r matches color and colour), {n} means exactly n times, and {n,m} means n to m times. A repeat symbol applies only to the one character (or one bracket ) right before it. Repeats also grab as much as they can (they are ): ".*" takes everything from the first quote to the last quote on the line, so to stay inside one pair of write "[^"]*".

04

Symbols that mark a position — ^ $ \b

^ is the start of a line and $ is the end. ^error matches lines that start with error, done$ matches lines that end with done, and ^$ matches an empty line. \b is a word boundary, so \bart\b finds art but not party. These symbols take up no characters; they only mark a position. Do not confuse them with a ^ at the front of brackets ([^0-9]), which means "not" — something completely different.

05

Groups and alternatives — ( ) |

red|blue means red or blue. ( ) turns several characters into one unit — (ab)+ matches ab, abab and ababab. also let you take out what was found: \1 \2 in , ${BASH_REMATCH[1]} in a , and m.group(1) in . That is why turning 2026-10-15 into 15.10.2026 takes just one line.

06

Using a symbol as a plain character — escaping

. * + ? ( ) [ ] { } ^ $ | \ all have special meanings. To find the character itself, put \ in front of it: a dot is \., a star is \*, an opening bracket is \(. If you write the 192.168.0.1 as it is, each . means "any character", so 192x168y0z1 matches too. And in the , always wrap the pattern in . Otherwise the shell changes * ? $ { } its own way before the even sees them.

07

Basic and extended grammar — why add -E

and read patterns in by default. In basic grammar + ? | ( ) { } are ordinary characters, so to use them as features you write \+ \| \( with a backslash. Add -E (grep -E, sed -E) to switch to and write the symbols as they are — when in doubt, always add -E. \d is a (PCRE) symbol, so in grep -E it is the letter d, not a digit. In tools write [0-9]; if you really want \d, use grep -P (). , , PHP and (rg) understand \d out of the box.

08

Commands built in on macOS, Linux and Windows

macOS and come with , , , find and . But the grep and sed on macOS are versions: there is no grep -P, you write [[:space:]] instead of \s, and sed -i needs '' after it when editing a file. Linux has the GNU versions, where -P, \s and \+ all work. On Windows, has and has , -match and -replace, and PowerShell understands \d as it is. Install or on Windows and you can use grep and sed too. The "Built-in by OS" table below collects examples.

09

Using regex in shell scripts and Python

In a , check a value with [[ $value =~ pattern ]]. It is true when it matches, so you can follow it with or use it in if, and the parts in ( ) go into ${BASH_REMATCH[1]}. the pattern makes bash compare it as plain text, so write the pattern without quotes or keep it in a like re='…' and use [[ $value =~ $re ]]. In , import re and use re.search (find), re.findall (find all), re.sub (replace) and re.fullmatch (check the whole text), and write the pattern as a raw with an r in front, like r"\d+".

At a glance

Regex symbol table

Common symbols with their meaning, an example and text that the example matches. Click an example to drop it into the tester below and see it work.

Symbol Meaning Example Matches
. Any one character abc · a1c
* The character before, 0 or more times ac · abbc
+ The character before, 1 or more times abc · abbc
? The character before, 0 or 1 time color · colour
{n,m} Repeat n to m times 12 · 2026
^ Start of a line error: disk full
$ End of a line all done
[abc] One of the characters in the brackets a · e
[^abc] One character not in the brackets x · -
[a-z] One character in a range Q · k
| Or red · blue
( ) Group several characters into one ab · abab
\ Use a symbol as a plain character (escape) .

Shorthand symbols

Symbol Same as Meaning Example
\d [0-9] One digit 2026
\w [A-Za-z0-9_] One word character (letter, digit or _) user_1
\s [ \t\n] One whitespace character (space, tab, newline) a b
\D \W \S [^0-9] … The opposite of each — not a digit, word character or whitespace abc
\b \< \> Word boundary — \bart\b finds art but skips party art
[[:space:]] \s POSIX name — a safe form that works in grep and sed everywhere, macOS included 42
BRE · ERE · PCRE

Basic and extended grammar

and read by default, so + ? | ( ) { } need a \ in front to work as features. Add -E for and write the symbols as they are.

Feature Basic — grep, sed Extended — grep -E, sed -E
1 or more times \+ +
0 or 1 time \? ?
Or a\|b a|b
Group \( \) ( )
Repeat n to m times \{n,m\} {n,m}

Ways to write symbols as they are grep -E sed -E awk [[ =~ ]] grep -P vim \v

\d \w \s are symbols. In grep -E, \d is the letter d, not a digit, so write [0-9]. When you need \d, use grep -P (), or . With the grep and sed on macOS, [[:space:]] is safer than \s.

On your computer

Built-in commands by OS

you can use right away without installing anything. Pick your operating system from the tabs.

  • grep -E Find lines that match a pattern ( version, so no -P) grep -E 'ERROR|WARN' app.log
  • sed -E Find and replace — when editing a file, -i needs '' after it sed -E -i '' 's/[[:space:]]+$//' notes.txt
  • awk Print only the you want from matching lines awk '/ERROR/ {print $1, $3}' app.log
  • find -E Find file names with a (-E for ) find -E . -regex '.*\.(jpg|png)'
  • perl replace with \d — installed out of the box perl -pe 's/(\d+)-(\d+)/$2-$1/g' a.txt
  • zsh [[ =~ ]] Check a value in , the default on macOS [[ $v =~ ^[0-9]+$ ]] && echo number
  • python3 's re module — the first run may ask you to install the python3 -c "import re; print(re.findall(r'\d+', 'a1b22'))"

On macOS the default shell is zsh and and are BSD versions. To work exactly like , install the GNU versions (ggrep, gsed) with brew install grep gnu-sed.

  • grep -E · -P · -o — \d with -P, only the matching part with -o grep -Po '\d{4}-\d{2}-\d{2}' app.log
  • sed -E -i Edit a file in place — GNU understands \s and \+ too sed -E -i 's/\s+$//' notes.txt
  • awk Put a on a (field) awk -F: '$1 ~ /^www/' /etc/passwd
  • find -regex Find file with a regex find . -regextype posix-extended -regex '.*\.(php|js)'
  • bash [[ =~ ]] Check a value and take ( ) out of [[ $s =~ ([0-9]+) ]] && echo "${BASH_REMATCH[1]}"
  • git grep Search quickly inside a only git grep -n -E 'TODO|FIXME'
  • python3 , included in most distributions python3 -c "import re; print(re.sub(r'\s+', ' ', 'a b'))"

On grep and sed are GNU versions, so they behave exactly like the practice in this lesson.

  • findstr Search in — only part of (no + ? |) findstr /R /N "^ERROR" app.log
  • Select-String 's — find lines that match a pattern Select-String -Path app.log -Pattern 'ERROR|WARN'
  • -match True when it matches; go into $Matches '2026-10-15' -match '^\d{4}-\d{2}-\d{2}$'
  • -replace Find and replace — understands \d and \s as they are (Get-Content a.txt) -replace '\s+$', '' | Set-Content a.txt
  • [regex]::Matches Find every match [regex]::Matches('a1b22', '\d+').Value
  • Where-Object Pick file names with a regex Get-ChildItem | Where-Object Name -match '\.(jpg|png)$'
  • WSL · Git Bash Install or to use as they are wsl grep -E 'ERROR|WARN' app.log
  • py Run with py once it is installed py -c "import re; print(re.findall(r'\d+', 'a1b22'))"

PowerShell uses .NET regex, so \d \w \s and ( ) groups work as they are. in Command Prompt can do much less, so PowerShell is recommended.

At a glance

Practical patterns you will use often

Patterns to copy and use right away. Click one to load it into the tester and see where it matches.

Practice window

Regex tester

Change the pattern and the matching parts of the text below light up at once. Feel free to edit the text too.

Matches and groups

This tester uses the 's () , so symbols such as \d work. To do the same in the , use -P, or change \d to [0-9] and use grep -E.

WATCH OUT

Common beginner mistakes

  • Always wrap the pattern in . Written bare, as in -E [0-9]{1,3}, the expands {1,3} into 1 and 3 and turns * and ? into file names.
  • grep starts in , so the | in grep 'a|b' is just a character. Add grep -E to use or (|), + and ? as features.
  • \d is not a digit in grep -E or -E (it is the letter d). Use [0-9] in shell tools, or grep -P or if you really need \d.
  • . means "any character". To find a dot, write \.. Written as it is, 192.168.0.1 also matches 192x168y0z1.
  • Inside brackets in shell tools, \ is a plain character. [^\s] means "any character except \ and s", so for a non-space character write [^[:space:]] or [^ ].
  • .* grabs as much as it can. To match the text inside one pair of quotes, narrow it with "not that character", as in "[^"]*".
  • Putting quotes around the pattern, as in [[ $v =~ "^[0-9]+$" ]], makes compare plain text instead of a . Write it without quotes or keep it in a (re='…').
  • The sed and grep on macOS are versions, so \s, \+ and grep -P may not work. With -E and [[:space:]] the same works on both macOS and .
🚀 Advanced learning — go deeper

Read user input

Asks the user for a value and stores it in a . You don't have to the variable first.

echo "What's your name?"# Print the question on the screen
read name# Read the answer into the variable name
echo "Hello, $name!"# Use the value you got

Current directory and subshells

Instead of the , the $PWD also tells you where you are. Commands wrapped in parentheses ( ) run in a separate , so a inside them does not change where you are outside.

echo "I am in $PWD"# Use the current through a
(cd /tmp; pwd)# Moves only inside the subshell → prints /tmp
pwd# Outside, you are still where you were

Clear the screen and find help

clear (or Ctrl-L) tidies up the screen. For a you don't know, there are three kinds of help: help for built-in commands, man for the manual, and info for detailed documents.

clear# Empty the screen (same as Ctrl-L)
help for# Help for a built-in command such as for
man ls# The manual page of (press q to leave)

Brace expansion

List values or a range inside { } and the makes many names at once. It is especially handy for building a folder tree in one line.

mkdir -p project/{src,tests,docs}# Make three folders at once
touch file{1..5}.txt# Make five files, file1.txt to file5.txt
cp config.yaml{,.bak}# Backup trick: config.yaml → config.yaml.bak

Delete safely

cannot be undone. -i (ask about each file) and -v (show what was removed) cut down on mistakes, and trash- sends files to the trash instead.

rm -i old.txt# Asks whether you really want to delete it first
rm -v *.tmp# Shows what it deleted
rm -r tempDir/# Deletes the folder and everything in it (careful!)

More useful ls options

change how sorts and formats its list. These three are worth learning.

ls -l# One per line, with details
ls -t# Most recently changed first
ls -R# Into every subfolder too ()

More grep options

make far more powerful. Combine search, line numbers, exclusion and counting.

grep -r "TODO" ./src# -r: search a whole folder recursively
grep -n "error" app.log# -n: with line numbers
grep -v "debug" app.log# -v: only the lines without the word (the opposite)
grep -c "error" app.log# -c: only how many lines

Edit streams with sed

edits text as it flows past. It can replace, delete and pick ranges, and -i edits the file itself (keep a backup).

sed 's/okay/great/g' file.txt# Every okay becomes great
sed '/^#/d' file.txt# Delete that start with #
sed -i.bak 's/old/new/g' file.txt# Edit the file itself + a .bak backup
sed -n '/error/p' log.txt# Print only the lines with error

Process columns with awk

splits each line on spaces (or the character given with -F) and handles the pieces as $1, $2 … It is strong at totals, filters and statistics.

echo 'a b c' | awk '{print $2}'# The second column → b
awk -F',' '{print $3}' data.csv# Split on commas, third column
awk -F',' '$2 > 25' people.csv# Lines whose second column is over 25
awk '{s+=$1} END{print s}' nums.txt# Total of the first column

cut, sort, uniq, and xargs

Joining small tools with gives you powerful data processing. turns the output of one into the of the next.

cut -d ',' -f 1 file.csv# Only the first comma-separated
sort file.txt | uniq -c# Sort, then count the duplicates
find . -name "*.tmp" | xargs rm -f# Pass the files found to and delete them
find . -name "*.txt" -print0 | xargs -0 rm# Safe even for file names with spaces (-0)

Here documents and here strings

<< EOF hands several lines of text to a as its input in one piece. <<< is a light way to feed in one short line.

cat << EOF# The lines up to EOF become the input
several lines of text EOF# Everything between the two EOFs is the content
grep "banana" <<< "apple banana grape"# One line of input with <<<

Standard error and /dev/null

Output () and errors (stderr) travel on different channels. 2> takes only the errors, 2>&1 sends errors to the same place as the output, and /dev/null is the place where things are thrown away.

command 2> error.log# Only the error messages go to a file
command > out.log 2>&1# Output and errors together into out.log
command > /dev/null 2>&1# Throw away both output and errors (quiet)

Process substitution

<() passes a command's output as if it were a file. It is handy for comparing the results of two commands directly, without temporary files.

diff <(ls dir1) <(ls dir2)# Compare two folder listings directly
while read l; do echo "$l"; done < <(ls)# set in the are still there after it

Command substitution

$() drops a command's result into a sentence like a value. Prefer $( ) to backticks (`) — it can be nested.

echo "There are $(ls | wc -l) files here"# Put the number of files into a sentence
today=$(date +%Y-%m-%d)# Today's date into a

Parameter expansion

Inside ${ } you can take a value out and cut or replace part of it at the same time. It is the most powerful tool for reshaping a 's value.

echo "${var/Some/A}"# Replace the first Some with A
echo "${var//Some/A}"# // replaces every Some with A
echo "${var:0:7}"# Only 7 characters from position 0 (a )
echo "${#var}"# Length of the string

Defaults and letter case

You can give a default when a is empty, or change upper and lower case in one go.

echo "${foo:-default}"# Use "default" when foo is empty
: "${NAME:=guest}"# Set NAME to "guest" if it is missing, and keep it
echo "${var^^}"# All upper case ( 4+)
echo "${var,,}"# All lower case

Trim paths

# cuts from the front and % from the back. Doubled (##, %%) they cut as much as they can — that is how you take just the file name or the folder out of a .

path="/usr/local/bin/run.sh"# An example path
echo "${path##*/}"# Remove up to the last / → run.sh ()
echo "${path%/*}"# Remove from the last / on → /usr/local/bin (dirname)
echo "${path%.sh}"# Remove only the .sh

Arrays

Put several values in parentheses; take one out with [number] and all of them with [@]. ${#array[@]} counts them.

array=(apple banana grape)# Make an of three
echo "${array[0]}"# The first one → apple (numbers start at 0)
echo "${array[@]}"# All of them → apple banana grape
echo "${#array[@]}"# How many → 3

Associative arrays

An made with -A stores "name → value" pairs (like a dictionary or map in other languages).

declare -A person# Declare an associative array
person[name]="Alice"# Store a value under the label name
echo "${person[name]}"# Take it out → Alice
for k in "${!person[@]}"; do echo "$k"; done# Go through every key

Built-in variables and arithmetic

fills in some for you. Arithmetic goes inside $(( )), including powers and remainders. For decimals, use .

echo "$?"# of the just before (0 = success)
echo "$RANDOM"# A random number from 0 to 32767
echo "$(( 2 ** 10 ))"# A power → 1024
echo "scale=2; 10/3" | bc# Decimal math → 3.33

Formatted output with printf

behaves a little differently from system to system. works the same everywhere and controls width, alignment and decimal places exactly.

printf "Hello, %s!\n" "world"# Puts the value where %s is → Hello, world!
printf "%.2f\n" 3.14159# Two decimal places → 3.14
printf "%05d\n" 42# Five digits padded with zeros → 00042

Clean branching with case

When you compare one value with many patterns, case is tidier than a chain of ifs (it is like switch in other languages).

case "$x" in# on the value of x
0) echo "zero";;# When it is 0
1) echo "one";;# When it is 1
*) echo "something else";; esac# * matches everything else

for, while, and until

for goes through a list or a range, while repeats as long as a is true, and until repeats as long as it is false. There is a C-style for as well.

for ((i=1; i<=3; i++)); do echo "$i"; done# C-style for
while (( count < 3 )); do ((count++)); done# While the condition is true
until (( count >= 3 )); do ((count++)); done# While the condition is false

Regex matching and file tests

=~ checks whether a fits a pattern. -e, -f, -d and friends check whether a file or folder exists and what kind it is.

if [[ "$email" =~ ^[a-z]+@[a-z]+\. ]]; then echo match; fi# Regular expression match
if [[ -f "$file" ]]; then echo "file exists"; fi# -f: is it a regular file?
if [[ -d "$dir" ]]; then echo "folder exists"; fi# -d: is it a folder?
if [[ -z "$name" ]]; then echo "empty"; fi# -z: is it empty?

Variable scope

local makes a that is used only inside a , and makes a constant that cannot change. declare sets properties such as integer (-i), lower case (-l) and upper case (-u).

greet() { local msg="Hello"; echo "$msg $1"; }# msg is not visible outside the function
readonly PI=3.14# A constant that cannot be changed
declare -i num=42; num+=10# Integer type → the math happens by itself (52)
declare -u up="hi"; echo "$up"# Always upper case → HI

Parse options with getopts

The standard tool for letting a take such as -v or -f filename. A colon (:) after a letter means "this option needs a value".

while getopts ":vf:" opt; do# v takes no value, f needs one
case $opt in# for each option
v) verbose=true ;;# With -v, turn verbose on
f) file="$OPTARG" ;; esac; done# The value of -f is in

source and export

source (or .) runs another file in the current to load its and settings. export passes a on to as well.

source ./lib/helpers.sh# Bring another file's functions and variables into the current shell
. ~/.bashrc# . is the short form of source
export API_KEY="abc123"# Let child processes see it too

Cleanup with trap

trap sets a to run when the receives a (exit, error, interrupt). It is especially useful for cleaning up temporary files.

TMP=$(mktemp)# Make a safe temporary file
cleanup() { rm -f "$TMP"; }# A clean-up
trap cleanup EXIT# Always clean up when the script ends
trap 'echo stopped; exit 1' SIGINT# Safe even when Ctrl-C is pressed

Defensive set options

set at the top of a make it tougher against errors. Use -e (stop on error), -u (no unset ) and -o pipefail (notice failures) together. -x is for .

set -euo pipefail# The standard first line of a sturdy script
set -x# Print each as it runs (debugging)
set +x# Turn debugging off

Background jobs and wait

Put & after a to run it in the background. jobs lists them, and wait waits until they finish.

sleep 5 &# Run in the background
jobs# List of the still running
wait# Wait until every background job has finished
time sleep 1# Measure how long a command takes

Reusable safety patterns

Defensive patterns that come up again and again in real : check required values, check that a exists, and stop right away on failure.

: "${VAR:?VAR is required}"# Stop with an error if VAR is missing
command -v jq && echo "jq found"# Check whether a command is installed
cp a b || { echo failed; exit 1; }# On failure, print a message and stop

Understand each set option

set -euo pipefail combines three . Once you know which accident each one prevents, you see why it became the standard.

set -e# Stop at once if any fails
set -u# Using an undefined is an error (catches typos)
set -o pipefail# If a step in the middle of a fails, the whole pipe fails

Control globbing with shopt

adjusts how file names are matched (). globstar lets ** reach into subfolders, and nullglob gives an empty value when nothing matches.

shopt -s globstar# ** matches into subfolders too ( 4+)
for f in **/*.sh; do echo "$f"; done# Every .sh file in every subfolder
shopt -s nullglob# No match gives an empty value instead of the pattern text

IFS and safe line reading

(the internal ) decides where words are split. To read a file safely one line at a time, use IFS= together with read -r.

IFS=',' read -ra f <<< "a,b,c"# Split on commas into the f
while IFS= read -r line; do# Keeps spaces and special characters
echo "$line"; done < file.txt# Reads safely one line at a time

Manage versions with nvm

Different projects may need different Node versions. installs several versions and switches between them.

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash# Install nvm (check the version number in the official docs)
nvm install 22# Install Node 22
nvm use 22# Use Node 22 in the current
node -v# Check the version you switched to

npm scripts and local binaries

The in run with _modules/.bin added to , so you can use the project's tools without installing them .

npm init -y# Make package.json quickly
npm install lodash# Add a dependency
npm install -D typescript# A development-only dependency
npm run build# Run scripts.build

One-off runs with npx

Use to run the latest version of a tool once, without a . It is especially useful for CLIs whose versions change often.

npx create-next-app@latest my-app# Example of scaffolding a project
npx prettier --write .# Run prettier, local or downloaded
npx --yes cowsay hello# Run once without asking for confirmation

AI coding agent install notes

Install them with the official install or as a global . Right after installing, check with the version .

curl -fsSL https://claude.ai/install.sh | bash# Claude (Anthropic)
curl -fsSL https://chatgpt.com/codex/install.sh | sh# OpenAI Codex
npm install -g @xai-official/grok# Grok CLI (an npm alternative, as an example)
claude --version && codex --version# Check the install (example)

Firebase and other essential CLIs

The , used for , sign-in and , is often installed together with pnpm, a fast manager.

npm install -g firebase-tools# Firebase CLI
firebase login# Sign in through the
firebase projects:list# List of projects
npm install -g pnpm# Install pnpm

PATH and permission issues

If the install worked but the can't be found, it is a problem. Check the location with which, and look over your settings.

which node npm# Where the are
echo "$PATH"# Check the search path
npm config get prefix# Where global installs go
command -v firebase || echo "not found"# Check whether it is installed

One-liner options by language

Almost every scripting language has an that "takes as an and runs it right away". Only the option letter differs; the way you use it is the same.

python3 -c "import sys; print(sys.version)"# one-liner
node -e "console.log(1 + 1)"# one-liner
perl -e 'print "hello\n"'# Perl one-liner
ruby -e 'puts (1..5).to_a'# Ruby one-liner
php -r 'echo PHP_VERSION;'# PHP uses -r

The pattern AI uses to edit files

When you ask an to change , the answer almost always looks like this: a small that reads the file, replaces a and writes it back, passed in with a . The key is to check first with assert that the thing to replace really is there.

python3 - <<'PY'# From here to PY is a Python program
p = "src/app.py"# of the file to change
s = open(p, encoding="utf-8").read()# Read the whole file
old = "before text"# The string to find (without this line you get a NameError)
new = "after text"# The string to put in
assert old in s# Stops here if the is missing (the most important line)
s = s.replace(old, new)# Replace
open(p, "w", encoding="utf-8").write(s)# Write it back
PY# End of the heredoc — exactly at the start of the line

Heredoc in practice — generating config files

are also the cleanest way to make multi-line settings or documents inside a . If the tag is not quoted, $variables are filled in on the spot.

cat <<EOF > .env# Tag not quoted → are filled in
PORT=$PORT# $PORT is saved as its real value
EOF# Ends here
cat <<'EOF' > template.txt# Quoted → $PORT stays as plain text
bash <<< "echo one-liner"# Pass just one line with a

sed in depth — target exactly the right lines

Put an address (line numbers or a ) in front and only those lines change. When -i edits a file directly, add an such as -i.bak — you keep a backup, and it works the same on macOS and .

sed -n '10,20p' log.txt# Print only lines 10 to 20
sed '/^#/d' config.txt# Delete that start with #
sed -i.bak 's/3000/8080/' config.txt# Edit the file, leaving a backup (.bak)
sed -E 's/([a-z]+)@([a-z.]+)/\2 \/ \1/' mail.txt# Swap the order with
sed 's/error/ERROR/gI' log.txt# Replace all, ignoring upper and lower case
printf 'appended\n' >> notes.txt# Add after the last line (works everywhere)

awk in depth — totals and formatting

shows its real strength in totals and formatting. Reading a table, grouping it by item and printing it neatly takes one line.

awk '{sum[$1] += $2} END {for (k in sum) printf "%-10s %5d\n", k, sum[k]}' sales.txt# Totals per item, printed as a table
awk -F, '{print $2}' data.csv# For , -F, splits on commas
awk 'NF > 0' notes.txt# Remove empty lines (a pattern alone prints the line)
awk '{n = split($0, a, "/"); print a[n]}' paths.txt# Only the file name from a
awk 'NR == FNR {m[$1] = $2; next} $1 in m {print $1, m[$1], $2}' a.txt b.txt# Join two files
awk 'BEGIN {printf "%.2f\n", 22 / 7}'# BEGIN alone makes a calculator

jq and xargs — the glue between languages

is handled with , and "run a for each result found" with . Knowing both greatly widens what you can connect with .

curl -s https://api.example.com/u | jq '.name'# One from JSON
jq -r '.items[] | .id' data.json# Spread an one item per line (-r removes the )
ls *.txt | xargs wc -l# Run a command for each file found
grep -rlZ TODO . | xargs -0 sed -i.bak 's/TODO/DONE/g'# Bulk edit with + (-Z and -0 keep file names with spaces safe, and backups are kept)

Greedy and lazy matching

* and + grab as much as they can (). Add ? after them (*? and +?) to grab as little as possible (lazy matching) — this only works in grammar ( -P, ). In basic and , narrow the range with "not that character" instead, as in [^"]*.

echo '<b>a</b><b>b</b>' | grep -Po '<b>.*</b>'# Greedy: one piece from the first <b> to the last </b>
echo '<b>a</b><b>b</b>' | grep -Po '<b>.*?</b>'# Lazy: <b>a</b> and <b>b</b> separately
grep -Eo '"[^"]*"' data.json# Extended grammar: narrow it to "anything but a quote"
grep -Po 'id=\K\d+' app.log# \K — check the first part but print only the number
python3 -c "import re; print(re.findall(r'\d+(?=ms)', 'took 2300ms'))"# Lookahead (?=…) — only the number right before ms

Backreferences — the same text again

Call a captured again inside the pattern with \1 to find "the same text appearing again". Use it to find or fix words typed twice by mistake.

grep -Ew '([a-z]+) \1' notes.txt# Find a word repeated twice in a row (the the)
sed -E 's/\b([a-z]+) \1\b/\1/g' notes.txt# Turn a doubled word into one
grep -E '^(.)(.).?\2\1$' words.txt# Words of up to 5 letters that read the same backwards (level, noon)
sed -E 's/(.*)=(.*)/\2=\1/' config.txt# Swap the two sides of key=value

The same task on each operating system

Compare side by side how each operating system does the same job. and macOS use and ; Windows uses 's and -replace.

grep -rn -E 'TODO|FIXME' .# Linux and macOS: search every file in the folder
Select-String -Path *.txt -Pattern 'TODO|FIXME'# Windows PowerShell: the same job
sed -i.bak -E 's/[[:space:]]+$//' notes.txt# Linux and macOS alike: remove trailing spaces (keeps a .bak backup)
(Get-Content notes.txt) -replace '\s+$', '' | Set-Content notes.txt# Windows PowerShell: the same job
findstr /R /C:"^[0-9][0-9]*$" numbers.txt# Windows : lines of digits only (no +, so [0-9][0-9]*)

rg, perl and git — faster, stronger tools

(rg) is faster than , understands \d as it is, and skips the files listed in on its own (brew install ripgrep, apt install ripgrep). , built into macOS and , is where comes from, and searches a 's and history with .

rg -n 'TODO|FIXME'# Everything under the , with line numbers
rg -o '\d{4}-\d{2}-\d{2}' -g '*.log'# Only the dates in .log files
perl -pe 's/(\d+)-(\d+)/$2-$1/g' a.txt# Perl: 12-34 → 34-12
perl -pi -e 's/foo/bar/g' *.txt# Perl: edit several files in place
git log --grep='fix.*login' -i --oneline# Search messages with a regex
git log -G 'apiKey' --oneline# Search code changes with a regex

More of Python's re

's re uses grammar, so \d \w \s, lazy matching and named all work. Write patterns as raw r"…" — a plain "\b" turns into a backspace character.

import re# Load the module
re.search(r"\d+", "a12b").group()# The first match → "12"
re.findall(r"\d+", "a12b345")# Every match → ["12", "345"]
re.sub(r"\s+", " ", "a b")# Replace → "a b"
re.split(r"[,;]\s*", "a, b;c")# Split with a regex → ["a", "b", "c"]
m = re.match(r"(?P<y>\d{4})-(?P<m>\d{2})", "2026-10")# Named groups — m["y"] is "2026"
pat = re.compile(r"error", re.I)# Build it once; re.I ignores case

awk and regex

uses . /pattern/ checks the whole line, $3 ~ /pattern/ checks only that , and gsub replaces. Give -F a to split on several at once.

awk '/ERROR|WARN/' app.log# The same as -E
awk '$4 ~ /^user=a/' app.log# Lines whose 4th column starts with user=a
awk '$3 !~ /INFO/ {print $3, $4}' app.log# Columns 3 and 4 of lines that are not INFO
awk '{gsub(/[0-9]+ms/, "N ms"); print}' app.log# Replace every value like 2300ms on the line
awk -F'[=: ]+' '{print $2}' config.txt# Treat =, : and runs of spaces all as separators

Adapted from Learn X in Y Minutes (Bash, CC BY-SA). Some commands are reference-only.

Lesson complete!Excellent — you just took another step forward.