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.
Sign up to keep track of your learning progress.
Log inPython 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 models, 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 is useful for running programs, managing files, and automating development. can also run through browsers, apps, notebooks, and APIs. A is one useful interface, not a requirement for every AI user.
Learn the basics, then , developer tools, and running other languages — all the way to automation.
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.
Shell has been a stable, universal computer language for decades. Learn it once and use it across macOS, Linux, servers, platforms, and AI tools.
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.
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."
#!/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
mkfifo "$PIPE"
Creates a . The request receives and the response we build both travel through this channel.
nc -l "$PORT"
nc (netcat) opens 8084 and waits for the browser to connect — a socket server in a single .
response()
Reads the request line (method and ), logs it, and returns index.html as an HTTP 200 response.
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 localhost:8084 in your browser. Not for production, but perfect for understanding how HTTP works.
Learn how to enter , understand the , and find your current location.
Practice creating, copying, moving, deleting, and reading files and folders.
Store reusable values and insert , results, and calculations into text.
Use if to choose behavior and for or while to repeat work.
Bundle reusable into , pass , and understand and .
Find matching lines, and deduplicate text, and count lines or words.
Connect output with | and results into files with > and >>.
Combine everything you learned into safer that validate inputs and automate real work.
Avoid and mistakes, and write defensive that stop safely on errors.
Learn to use from the : check versions, run , manage with , and run one-off tools with .
A short guide to installing coding agents and deploy CLIs in the . With Node and ready, most tools start with one .
The does not do everything itself — it conducts other languages. Learn one-line execution with -c, for multi-line programs, and the two tools reaches for most: and .
Use the basic command [] [target] structure
Check your location and move between folders
Print text with
Find help with man and --help
A is a text window for giving instructions to a computer. The $ or % means the is ready; type one and press Enter.
Most contain an action, , and a target. For example, -l Documents means list files, show details, and use the Documents folder.
Your always matters. Use to see it, to move, and to inspect its contents. ~ means your and .. means the parent folder.
Select a command to place it in the terminal.
Create folders and empty files
Copy, move, rename, and delete files
Read files with , , and
Use destructive safely
creates folders and creates empty files. mkdir -p a/b/c conveniently creates every missing parent folder.
keeps the original and makes a copy. moves an item, and mv old new also renames it.
prints a whole file, while and show only the beginning or end. deletes immediately without using the Trash, so use it carefully.
Select a command to place it in the terminal.
Create and read variables
Quote variables safely
Calculate with $(( ))
Capture command output with $( )
Create a with name=value and read it with $name. Never put spaces around =: name=Lyen works, while name = Lyen does not.
Use "$name" so values containing spaces stay together. This is one of the most important safe- habits.
$(( 3 + 4 )) returns 7. $() captures a command result so you can store it in a or insert it into text.
Select a command to place it in the terminal.
with if / elif / else
Compare , numbers, and files with [[ ]]
Process lists with for
Distinguish numeric and string comparisons
In if ; then ... fi, the inner run only when the condition is true. Add elif and else for more , and always close with fi.
Use == and != for , -gt/-lt/-eq for numbers, and -f or -d to check files and folders.
for item in list; do ... done puts each list item into a . You can over {1..5} or over files.
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}.
Select a command to place it in the terminal.
Define and call a function
Use function arguments such as $1
Explain #!/bin/bash
Understand
name() { ; } turns a command sequence into a reusable name. Inside a , $1 and $2 hold incoming .
Save in a .sh file to run them again. tells the system to execute that file with , including on a macOS zsh setup.
Run +x hello.sh before ./hello.sh. Read incoming values with $1, $2, $@, and $#.
Select a command to place it in the terminal.
Find matching lines with
Use grep -i and -n
Sort lines with sort
Count with
word file prints only matching lines. Add -i for case-insensitive search, -n for line numbers, or -r for recursive folder search.
can find and replace text, while splits each line into fields so you can select columns and process tabular data.
The tool people type as is ripgrep. Like in this lesson it finds matching lines, but by default it searches a whole folder quickly and skips files listed in .gitignore. Its are not all the same as grep, so learn grep first and add rg later. The practice here does not run rg, so try it on your own computer.
orders lines, combines adjacent duplicates, and -l counts lines. Together they make quick statistics.
Select a command to place it in the terminal.
Connect commands with |
Save output with >
Append output with >>
Understand standard-output flow
commandA | commandB sends A’s output directly into B. Small tools combine into powerful one-line workflows.
> overwrites a file, >> appends, and < uses a file as input. Use 2> to errors separately.
Insert in the middle of a to pass the stream 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 append instead of overwrite — handy for keeping a log while still watching the result.
Select a command to place it in the terminal.
Read success or failure through
Chain success and failure with && and ||
Process many files with for
Understand scheduled execution with
Every returns 0 for success or another number for failure. reads the previous result, and A && B runs B only when A succeeds.
Combine with file to process many items, such as copying every photo into a dated backup folder.
runs at fixed times. Its five time fields are minute, hour, day, month, and weekday; 0 3 * * * means every day at 3 a.m.
Select a command to place it in the terminal.
Explain double, single, and unquoted text
Understand word splitting and globbing
Use set -euo pipefail
Always quote expansions
"$var" expands the but preserves spaces; '$var' keeps everything literal; unquoted $var may split at spaces and expand characters.
Unquoted values split into multiple and * or ? can turn into filenames. A single filename containing spaces can then be mistaken for two.
set -euo pipefail stops on errors, rejects undefined , and catches failures inside . can find many problems before execution.
Select a command to place it in the terminal.
Check the Node.js version with -v
Run a file with node app.js
Install packages and run scripts with npm
Run a tool once with npx without a global install
runs outside the — in terminals and servers. Web apps, tools, build , and many coding agents depend on it. After basics, Node is the next foundation for installing developer tools.
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 syntax errors print an error message.
installs and manages libraries. lists name, version, , and dependencies. npm install fetches dependencies; npm run start runs a script. runs a package once without a permanent global install.
Select a command to place it in the terminal.
Explain why is a prerequisite for many tools
Know the common install commands for Claude Code, Codex, Grok, and
Tell global install (-g) apart from one-off runs ()
Verify installs with version commands
Modern development is not only an editor. coding agents (Grok Build, OpenAI Codex, Claude Code), deploy CLIs (Firebase tools), and managers run in the . Lesson 10 Node and skills are the starting point.
Official methods can change — always prefer the vendor docs. Typical starts: Claude Code 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.
Prefer reading | from trusted official domains. If global hits permission errors, fix instead of using . In teams and CI, pin tools as devDependencies so versions stay consistent.
Select a command to place it in the terminal.
Run one-liners in other languages with -c and -e
Save a program to a file and run it with python3 file.py
Pass a multi-line program to a with a heredoc (<<PY)
Edit text across a file with sed
Pick out columns and total them with awk
Check AI-generated code before you run it
Doing every calculation in alone hits a wall fast. Instead the shell decides who to call and when: Python 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.
Most languages accept code as an and run it immediately: -c "code", -e "code", perl -e, ruby -e. Just replacing your calculator with python3 -c "print(2**10)" makes the far more powerful.
If a program is worth keeping, put it in a file. Write the code into hello.py and hello.py runs it as is. Add the you met in Lesson 5 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.
For a program 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 Python on . The lone - means "read the code from standard input instead of a file." This is the form coding agents often use when they edit your files.
Quote the closing tag (<<'PY') and the body is passed through literally. Leave it unquoted (<<PY) and the first substitutes $variables and $() inside it. Python code rarely contains $, but a or that does will break silently — so the tag is the default when passing code.
'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. Add -i and it edits the file itself. The delimiter need not be / — for , s|/old/path|/new/path| reads much better. To edit the file itself, use sed -i.bak 's/find/replace/' file: it keeps the original as file.bak and works identically on macOS and Linux. On Linux (GNU sed) you may drop the backup name and write sed -i, but macOS sed requires a name after -i, so the bare form fails there (to edit without a backup on macOS, write sed -i '' '…' file).
is not a ; it is a language. It splits each line on whitespace into $1, $2, $3, with NF as the column 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.
Programs written to read and write standard output chain freely through . sales.txt | '{print $2}' | -n | -3 means "read the file, take the second column, sort numerically, keep the three largest" — all in one line. awk and are joined this way; Python takes its code through -c or a instead. That is what it means for the to be the conductor.
usually answers in exactly this form. Before pasting it, check three things: read the file it touches, look for or > that overwrite, and back up anything important first with original original.bak. Being able to read means being able to verify what the AI gave you.
Select a command to place it in the terminal.
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 screenread name# Read the answer into the variable nameecho "Hello, $name!"# Use the value you gotInstead 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 /tmppwd# Outside, you are still where you wereclear (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 forman ls# The manual page of (press q to leave)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 oncetouch file{1..5}.txt# Make five files, file1.txt to file5.txtcp config.yaml{,.bak}# Backup trick: config.yaml → config.yaml.bakcannot 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 firstrm -v *.tmp# Shows what it deletedrm -r tempDir/# Deletes the folder and everything in it (careful!)change how sorts and formats its list. These three are worth learning.
ls -l# One per line, with detailsls -t# Most recently changed firstls -R# Into every subfolder too (recursive)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 Aecho "${var//Some/A}"# // replaces every Some with Aecho "${var:0:7}"# Only 7 characters from position 0 (a )echo "${#var}"# Length of the stringYou 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 itecho "${var^^}"# All upper case ( 4+)echo "${var,,}"# All lower case# 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 pathecho "${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 extensionPut several values in parentheses; take one out with [number] and all of them with [@]. ${#array[@]} counts them.
array=(apple banana grape)# Make an of threeecho "${array[0]}"# The first one → apple (numbers start at 0)echo "${array[@]}"# All of them → apple banana grapeecho "${#array[@]}"# How many → 3An made with -A stores "name → value" pairs (like a dictionary or map in other languages).
declare -A person# Declare an associative arrayperson[name]="Alice"# Store a value under the label nameecho "${person[name]}"# Take it out → Alicefor k in "${!person[@]}"; do echo "$k"; done# Go through every keyfills 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 32767echo "$(( 2 ** 10 ))"# A power → 1024echo "scale=2; 10/3" | bc# Decimal math → 3.33behaves 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.14printf "%05d\n" 42# Five digits padded with zeros → 00042When 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 elsefor 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 forwhile (( count < 3 )); do ((count++)); done# While the condition is trueuntil (( count >= 3 )); do ((count++)); done# While the condition is false=~ 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 matchif [[ -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?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 functionreadonly PI=3.14# A constant that cannot be changeddeclare -i num=42; num+=10# Integer type → the math happens by itself (52)declare -u up="hi"; echo "$up"# Always upper case → HIThe 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 (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 sourceexport API_KEY="abc123"# Let child processes see it toomake far more powerful. Combine recursive search, line numbers, exclusion and counting.
grep -r "TODO" ./src# -r: search a whole folder recursivelygrep -n "error" app.log# -n: with line numbersgrep -v "debug" app.log# -v: only the lines without the word (the opposite)grep -c "error" app.log# -c: only how many linesedits 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 greatsed '/^#/d' file.txt# Delete comment lines that start with #sed -i.bak 's/old/new/g' file.txt# Edit the file itself + a .bak backupsed -n '/error/p' log.txt# Print only the lines with errorsplits each line on spaces (or the character given with -F) and handles the pieces as columns $1, $2 … It is strong at totals, filters and statistics.
echo 'a b c' | awk '{print $2}'# The second column → bawk -F',' '{print $3}' data.csv# Split on commas, third columnawk -F',' '$2 > 25' people.csv# Lines whose second column is over 25awk '{s+=$1} END{print s}' nums.txt# Total of the first columnJoining 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 columnsort file.txt | uniq -c# Sort, then count the duplicatesfind . -name "*.tmp" | xargs rm -f# Pass the files found to and delete themfind . -name "*.txt" -print0 | xargs -0 rm# Safe even for file names with spaces (-0)<< 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 inputseveral lines
of text
EOF# Everything between the two EOFs is the contentgrep "banana" <<< "apple banana grape"# One line of input with <<<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 filecommand > out.log 2>&1# Output and errors together into out.logcommand > /dev/null 2>&1# Throw away both output and errors (quiet)<() 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 directlywhile read l; do echo "$l"; done < <(ls)# set in the are still there after it$() 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 sentencetoday=$(date +%Y-%m-%d)# Today's date into a 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 filecleanup() { rm -f "$TMP"; }# A clean-up trap cleanup EXIT# Always clean up when the script endstrap 'echo stopped; exit 1' SIGINT# Safe even when Ctrl-C is pressedset 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 scriptset -x# Print each as it runs (debugging)set +x# Turn debugging offPut & after a to run it in the background. jobs lists them, and wait waits until they finish.
sleep 5 &# Run in the backgroundjobs# List of the still runningwait# Wait until every background job has finishedtime sleep 1# Measure how long a command takesDefensive 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 missingcommand -v jq && echo "jq found"# Check whether a command is installedcp a b || { echo failed; exit 1; }# On failure, print a message and stopset -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 failsset -u# Using an undefined is an error (catches typos)set -o pipefail# If a step in the middle of a fails, the whole pipe failsadjusts 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 subfoldershopt -s nullglob# No match gives an empty value instead of the pattern text(the internal field separator) 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 fwhile IFS= read -r line; do# Keeps spaces and special characters echo "$line"; done < file.txt# Reads safely one line at a timeDifferent 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 22nvm use 22# Use Node 22 in the current node -v# Check the version you switched toThe in run with _modules/.bin added to , so you can use the project's tools without installing them globally.
npm init -y# Make package.json quicklynpm install lodash# Add a runtime dependencynpm install -D typescript# A development-only dependencynpm run build# Run scripts.buildUse to run the latest version of a tool once, without a global install. It is especially useful for CLIs whose versions change often.
npx create-next-app@latest my-app# Example of scaffolding a projectnpx prettier --write .# Run prettier, local or downloadednpx --yes cowsay hello# Run once without asking for confirmationInstall 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 Code (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)The , used for deploying, sign-in and hosting, is often installed together with pnpm, a fast manager.
npm install -g firebase-tools# Firebase CLIfirebase login# Sign in through the firebase projects:list# List of projectsnpm install -g pnpm# Install pnpm globallyIf 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 programs areecho "$PATH"# Check the search npm config get prefix# Where global installs gocommand -v firebase || echo "not found"# Check whether it is installedAlmost every scripting language has an that "takes code 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)"# Python one-linernode -e "console.log(1 + 1)"# one-linerperl -e 'print "hello\n"'# Perl one-linerruby -e 'puts (1..5).to_a'# Ruby one-linerphp -r 'echo PHP_VERSION;'# PHP uses -rWhen you ask an to change code, the answer almost always looks like this: a small Python program 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 programp = "src/app.py"# of the file to changes = open(p, encoding="utf-8").read()# Read the whole fileold = "before text"# The string to find (without this line you get a NameError)new = "after text"# The string to put inassert old in s# Stops here if the target is missing (the most important line)s = s.replace(old, new)# Replaceopen(p, "w", encoding="utf-8").write(s)# Write it backPY# End of the heredoc — exactly at the start of the lineare 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 inPORT=$PORT# $PORT is saved as its real valueEOF# Ends herecat <<'EOF' > template.txt# Quoted → $PORT stays as plain textbash <<< "echo one-liner"# Pass just one line with a Put an address (line numbers or a ) in front and only those lines change. When -i edits a file directly, add an extension such as -i.bak — you keep a backup, and it works the same on macOS and Linux.
sed -n '10,20p' log.txt# Print only lines 10 to 20sed '/^#/d' config.txt# Delete comment lines 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 groupssed 's/error/ERROR/gI' log.txt# Replace all, ignoring upper and lower caseprintf 'appended\n' >> notes.txt# Add after the last line (works everywhere)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 tableawk -F, '{print $2}' data.csv# For , -F, splits on commasawk '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 filesawk 'BEGIN {printf "%.2f\n", 22 / 7}'# BEGIN alone makes a calculatoris 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 field from JSONjq -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 foundgrep -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)Adapted from Learn X in Y Minutes (Bash, CC BY-SA). Some commands are reference-only.