You know the basics — now for the real power. Chain commands into pipelines, search and reshape text, write scripts that automate the boring, manage permissions and processes, and SSH properly with keys. With a pipeline-capable practice terminal to play in.
| — the idea that changes everythingThis one concept is what makes the Terminal genuinely powerful. A pipe (the | character, Shift-backslash on a Mac) takes the output of one command and feeds it straight into the next as its input. You build a little assembly line.
Read left to right: “print the log → keep only lines with ‘error’ → count them.” Three simple tools, combined, answer a real question in one line: how many errors are in this log?
| feeds one command’s output into the next. Chain small tools to answer big questions in a single line.You met > in the beginner course (send output into a file). Here’s the fuller set:
command > file — write output to a file (replacing it).command >> file — append to the end instead.command < file — feed a file in as input.command 2> errors.txt — send just the error messages somewhere (that 2 means “the error channel”).command > out.txt 2>&1 — send normal output and errors to the same place.Every command actually has two output taps: normal results and error messages. Usually they both hit the screen, but you can direct each wherever you like — handy when saving a job’s output or its errors for later.
> writes, >> appends, < feeds in, and 2> catches errors separately. Output has two taps: results and errors.Wildcards let one command hit lots of files. The shell expands them before the command runs:
* — matches anything. ls *.txt lists every .txt file. rm *.tmp deletes all .tmp files.? — matches exactly one character. ls page?.html matches page1.html, page2.html…[ ] — matches one of a set. ls img[123].png matches img1/2/3.png.* with rm. rm * deletes everything in the folder. And a stray space — rm * .txt instead of rm *.txt — is famously how people wipe a whole folder by accident. Type wildcards with ls first to see what they’ll match, then swap in the real command.*, ? and [ ] match many files at once. Preview with ls before doing anything destructive.grep — find a needle in any haystackgrep searches for lines containing some text — in a file, or in whatever’s piped into it. It’s probably the command you’ll reach for most.
Its real power shows on the end of a pipe: ls | grep report finds files with “report” in the name; history | grep ssh finds every ssh command you’ve run. Anything that produces lines, grep can sift.
grep pattern file finds matching lines; -i ignores case, -v inverts, -c counts. Superb on the end of a pipe.find — locate files anywheregrep looks inside files; find locates the files themselves, by name, type, size or age, searching down through every sub-folder.
The . means “start here, in the current folder.” find is how you answer “where on earth did I put that file?” or “what’s eating all my disk space?”
find . -name "…" hunts down files by name/type/size/age through every sub-folder. grep searches inside; find searches for.A few more small tools that shine in pipelines:
wc -l — count lines (-w words, -c characters).sort — sort lines (-r reverse, -n numeric).uniq — collapse repeated adjacent lines (-c counts each). Usually sort | uniq.head -n 5 / tail -n 5 — first / last 5 lines.Now try it for real. This practice terminal understands pipes and all of the above. There’s a server.log and a names.txt waiting. Follow the steps — tap a command to drop it in, then press Return.
cat server.loggrep error server.logcat server.log | grep error | wc -l 🎉cat names.txt | sort | uniq -chelp, ls, ls *.txt, grep -c error server.log, NAME=Chris then echo hi $NAME.
wc, sort, uniq, head/tail are pipeline building blocks. sort | uniq -c is the classic “count how many of each.”PATHThe shell can remember values in variables. Set one with NAME=value (no spaces around the =), and use it later with a $ in front:
Some variables are set for you, and shared with programs you run — these are environment variables. The most important is PATH: the list of folders the shell searches to find commands. When you type ls, the shell looks through PATH to find the actual ls program.
export NAME=value makes a variable available to programs you launch, not just the shell itself. You’ll see export a lot in setup guides.
NAME=value stores a value; $NAME uses it. PATH is the list of places the shell looks to find commands.An alias is a shortcut you invent for a longer command:
Typed like that, it lasts only for this session. To keep it forever, add the line to your shell’s config file. On a modern Mac the shell is zsh, so that file is ~/.zshrc (older systems use ~/.bashrc). Edit it, add your aliases, save, and open a new Terminal — they’re always there.
And a few genuine time-savers:
!! — “the last command again.” Forgot sudo? Just type sudo !!.!$ — “the last thing from the previous line” (usually a filename), so you don’t retype it.history — show everything you’ve run (great piped into grep).alias makes shortcuts (save them in ~/.zshrc); Ctrl+R, !! and !$ save you huge amounts of typing.A script is just a file with a list of commands, run top to bottom. Anything you can type, you can save and re-run forever. Create a file backup.sh containing:
Two things make it work:
#!/bin/bash (the “shebang”), tells the Mac “run this with bash.”chmod +x backup.sh (more on chmod shortly).Then run it with ./backup.sh (the ./ means “the one right here”). From then on, one command does the whole job.
#!/bin/bash, make it executable with chmod +x, run it with ./name.sh.Scripts get powerful when they can repeat and decide. Two workhorses:
A loop — do something to each item:
A decision — do something only if a condition holds:
And command substitution — drop the result of one command into another with $(…):
for…do…done repeats, if…then…fi decides, and $(command) drops one command’s result into another. That’s real automation.Every file carries permissions: who may read it, write (change) it, and execute (run) it. Run ls -l and each line starts with something like -rwxr-xr--. Tap the parts to decode it:
One type flag, then three groups of rwx: what the owner, the group, and everyone else is allowed to do.
You change them with chmod. The quick way uses numbers — chmod 755 file (owner can do everything, others can read & run) or chmod 644 file (owner read/write, others read). The friendly way: chmod +x script.sh just adds “executable.” On a server, permissions are how you keep private files private.
chmod +x makes a script runnable; chmod 644/755 are the common presets.Every running program is a process with a number (a “PID”). Sometimes you need to see them or stop one:
top — a live dashboard of what’s running and what’s using the CPU (press q to quit).ps aux | grep node — find a specific program that’s running.kill 12345 — politely stop the process with that PID. kill -9 12345 forces it (last resort).And running things in the background so your Terminal stays free:
& to the end — ./longjob.sh & runs it in the background.jobs lists background jobs; fg brings one back to the foreground.top and ps show what’s running; kill PID stops it; & runs a job in the background so you can keep working.In the beginner course you connected with a password. The professional way is an SSH key: a matched pair of files — a private key that stays secret on your Mac, and a public key you put on the server. They only work as a pair, so it’s both more convenient and more secure than a password.
Set it up once:
After that, ssh chris@your-server just lets you in — no password typed. Behind the scenes the two keys perform a secret handshake.
~/.ssh/id_ed25519, no .pub) is like the master key to your house. Never send it to anyone, never paste it anywhere, never put it on a server. Only ever share the .pub (public) one.ssh-keygen makes a key pair; ssh-copy-id puts the public half on the server; then you log in with no password. Guard the private key with your life.SSH gets you a Terminal on the server. To move files across, two commands — they’re like cp, but one end is a remote machine:
For anything bigger — a whole website folder, or a repeated backup — use rsync. It’s smarter: it only copies what actually changed, so the second run is near-instant.
Two last power tools worth knowing exist, for when you’re ready:
~/.ssh/config) lets you save a server so you can just type ssh myserver instead of the full address.tmux keeps a session alive on the server even if your connection drops — essential for long jobs, so they don’t die when your laptop sleeps.scp copies single files to/from a server; rsync syncs whole folders efficiently. An ~/.ssh/config saves typing; tmux keeps long jobs alive.Instant feedback on each.