Exit Codes: Using $? and && ||
What you'll be able to do
- Check whether the last command succeeded or failed with `echo $?`
- Write "on success" and "on failure" branches with `&&` and `||`
- Report success or failure to the caller with `exit 0` and `exit 1`
Prerequisites (read these first)
What You'll Learn
- The idea of an exit status (exit code) that signals success or failure
- How to check the result of the previous command with
$? - How to branch on "if it succeeded" and "if it failed" with
&&and|| - A first step toward handling errors properly in shellAn interactive program that reads the commands you type and runs them. scripts
Words used here
- Exit status: the number a command returns when it finishes. Exit code, exit status, and return code all name the same thing.
- Variable: a named box that holds a value.
$?is a special variable the shell fills in for you. - Shell script: a file with commands written out in order.
Every command used here -- ls, echo, cd, mkdir -- leaves your existing files alone, so try them freely.
Quick Summary
- Every command returns a number when it finishes (
0means success, anything else means failure) - Want to see the last result?
echo $? - Run next on success →
&& - Run next on failure →
||
1. What Is an Exit Status?
Conclusion: An exit status is the number a command returns.
0means success;1to255mean failure.
0 means success, anything else means failure.The basic rule
| Number | Meaning |
|---|---|
0 |
Success |
1–255 |
Failure (some problem) |
"0 means success" runs against intuition. Lock it in first.
2. Why Does the Exit Status Matter?
Conclusion: The exit status is what lets you automate "run the next step only when this one succeeded."
Judging success only by what is printed on screen is risky. A command can fail even when no "Error" text appears.
Relying on the machine-readable exit status is far safer.
3. Check the Result with $?
Conclusion:
$?holds the exit status of the last command. Useecho $?to see it.
The exit status of the command you just ran is stored in a special variable called $?. The shell fills it in for you.
$ ls /etc
hosts passwd ...
$ echo $?
0
0! So ls succeeded.ls on a pathA string that describes the location of a file or directory. that doesn't exist.$ ls /not-exist
ls: cannot access '/not-exist': No such file or directory
$ echo $?
2
2. That is a different number from before.0. ls returns 2 for a "file not found" error.0 or not.$? only remembers the result of the immediately preceding command.
Run echo $? twice in a row and the second one reports the first echo. That one succeeded, so you get 0. Check it only once.
4. Chain "on success" with &&
Conclusion:
cmd1 && cmd2runs cmd2 only when cmd1 succeeds (returns0).
&& is the symbol that means "if the left side succeeds, run the right side too".
$ mkdir backup && cp data.txt backup/
cp only if mkdir succeeded"?mkdir backup fails, cp does not run at all. That happens when you lack permissionThe read / write / execute access rules set on a file or directory. to create the directoryA container that organizes files. Same idea as a "folder" on Windows or macOS., for example.# Run tests only if the build succeeds $ make && make test # List the contents only if the cd succeeds $ cd /var/log && ls
Think of && as "proceed once the precondition is met". It safely chains steps where you want to stop as soon as something fails.
5. Chain "on failure" with ||
Conclusion:
cmd1 || cmd2runs cmd2 only when cmd1 fails. Use it for error handling.
|| is the opposite of &&. It means "if the left side fails, run the right side".
$ cd /var/log || echo "Could not move into the directory"
cd fails it prints a message. And when it succeeds, nothing is printed?cd succeeds, the echo never runs. || is often used as a safety net for when things go wrong.# Prompt to install if a command is missing $ which jq || echo "jq is not installed. Please install it." # Exit the script if the step fails $ cp data.txt backup/ || exit 1
&& vs || at a glance
cmd1 && cmd2 → cmd2 runs if cmd1 [succeeds] cmd1 || cmd2 → cmd2 runs if cmd1 [fails]
Remember it as "&& proceeds on success" and "|| proceeds on failure".
6. Combining && and ||
Conclusion:
cmd && on-success || on-failurewrites "do A on success, B on failure" in one line.
Chaining && and || lets you act one way on success and another way on failure.
$ ping -c1 example.com > /dev/null && echo "Connection OK" || echo "Connection NG"
echo "Connection OK" -- the failure action runs too.if statement is safer.A && B || C is not the same as if A then B else C. If B fails, C also runs.
When you need reliable branching, use an if statement. The next-reading article covers how.
7. Common Beginner Pitfalls
Conclusion: The easy mistakes are getting "0 means success" backwards and reading
$?too late.
7-1. Remembering "0 means success" backwards
7-2. Lina gets stuck: reading $? too late
$ ls /not-exist $ pwd # ← an extra command slipped in $ echo $? # this shows pwd's result (0, success)
0. Is the exit status broken?$? only remembers one command back.pwd I slipped in replaced it?pwd succeeds, so the value became 0. The result from ls was already overwritten.Check $? right after the command you care about. Any command in between overwrites it.
7-3. Returning an exit status yourself
When you want a script to report success or failure to its caller, use exit.
exit 0 # end as success exit 1 # end as failure
If you call exit without a number, it returns the exit status of the last command as-is.
8. Hands-On Exercises
Conclusion: Three exercises — check, run-on-success, run-on-failure — to practice
$?,&&, and||.
Exercise 1: Run one command, then print its exit status right after.
Show Hint 1 (Direction)
The last result sits in a special variable the shell fills in. Print its contents on screen.
Show Hint 2 (Command name)
The variable is $?. Print it with echo.
Show Answer
$ ls $ echo $?
0
ls succeeded, so you get 0. Point it at a directory that does not exist and the number changes to something other than 0.
Exercise 2: Print "Created" only when mkdir test-dir succeeds.
Show Hint 1 (Direction)
Join two commands on one line. Use the symbol that runs the right side only when the left side succeeds.
Show Hint 2 (Command name)
The symbol is &&. Print with echo.
Show Answer
$ mkdir test-dir && echo "Created"
Created
Run the same line a second time and mkdir fails, so "Created" does not appear. Remove the directory afterwards with rmdir test-dir.
Exercise 3: Try to cd into a directory that does not exist, and print "Cannot move" only when it fails.
Show Hint 1 (Direction)
Same shape as Exercise 2, with the symbol reversed. Use the one that runs the right side only when the left side fails.
Show Hint 2 (Command name)
The symbol is ||. Move with cd.
Show Answer
$ cd /not-exist || echo "Cannot move"
bash: cd: /not-exist: No such file or directory Cannot move
You see both the error message from cd itself and the message you printed.
9. Review
0 is success, anything else is failure.echo $?, but only for the one command just before.&& proceeds on success while || proceeds on failure. I have that.exit 0 and exit 1.10. Copy-Paste Templates
Conclusion: Keep the common patterns — check, on-success, on-failure, branch, and exit — within reach.
Common patterns to keep handy
# Check the last exit status echo $? # Run next only on success commandA && commandB # Run next only on failure commandA || commandB # A on success, B on failure (simple branch) command && echo "OK" || echo "NG" # Exit the script if the step fails command || exit 1 # End a script explicitly as success / failure exit 0 # success exit 1 # failure
Today's 3-Line Summary
- A command returns a number when it finishes.
0is success, anything else is failure - Read the last result with
echo $?, with no other command in between &&proceeds on success.||proceeds on failure