Shell, explained

&&, || and ; in the terminal: what's the difference?

mkdir backup && cp notes.txt backup/

All three run one command after another. && runs the next one only if the previous one succeeded (exit status 0), || only if it failed, and ; runs it no matter what happened.

&& stops at the first failure

backup already exists, so mkdir fails with exit status 1, and && skips the copy.

$

Tap a part of the command to find it below

$ mkdir backupEXIT 1
mkdir: backup: File existsstderr
&&

exit 1: mkdir failed, so cp is skipped

$ cp notes.txt backup/SKIPPED

not run

Tap any part of the command to see what it does

|| runs a fallback

grep -q prints nothing; it only reports through its exit status. No TODO means exit 1, so || runs echo.

$

Tap a part of the command to find it below

$ grep -q TODO notes.txtEXIT 1

no output

||

exit 1: grep failed, so echo runs

$ echo "Nothing to do"OUTPUT
Nothing to do
Tap any part of the command to see what it does

; does not care

cd fails, and ls runs anyway, in the folder you were already in.

$

Tap a part of the command to find it below

$ cd /missingEXIT 1
bash: cd: /missing: No such file or directorystderr
;

ls runs next, whatever happened

$ lsOUTPUT
notes.txt
photo.png
todo.txt
Tap any part of the command to see what it does

Part by part

mkdir backup
Creates a folder. Exits with 0 if that worked, and 1 if it did not (here, because it already exists).
&&
Runs the next command only if the last one exited with 0.
cp notes.txt backup/
Copies the file into the folder.
||
Runs the next command only if the last one exited with something other than 0.
;
Runs the next command regardless.

Common mistakes

Reading a && b || c as if/else

c runs when a fails, but also when a succeeds and b fails. For a real if/else, write if a; then b; else c; fi.

cd dir; rm *

If cd fails, ; still runs rm * in the folder you are in. cd dir && rm * stops when cd fails.

Try it

$ mkdir -p backup && cp notes.txt backup/

-p makes mkdir succeed when the folder exists.

$ ping -c1 example.com && echo up || echo down

A quick reachability check.

$ false; echo $?

$? holds the last exit status: prints 1.

Questions

What is an exit status?

A number every command returns when it finishes: 0 means success, anything else means some kind of failure. echo $? shows the last one.

Can I chain more than two commands?

Yes. In a && b && c, each step runs only if all the earlier ones succeeded.

What does a single & do?

It runs the command in the background and starts the next one right away, without waiting.

Terminaster

Ask about any command and get a picture like this one.

The Terminaster tutor draws these visuals for your own questions, then turns what you learned into spaced-repetition cards so it sticks.