Bash & the POSIX Shell Module 4
Exit status, tests and branching interview questions
Interview questions on exit status, tests and branching: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher to mid
Which command runs after && and which after ||, and why is a && b || c not an if and else?
Answered in the lesson Exit status, &&, || and command lists
-
Fresher to mid
Why should variables inside [ ] always be quoted?
Answered in the lesson test and [ ]: file, string and number checks
-
Mid
How is [[ ]] different from [ ] in Bash?
Answered in the lesson [[ ]]: patterns, regex and BASH_REMATCH
-
Fresher to mid
When would you use case instead of if and elif in a shell script?
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
A deploy script ends with build && upload || restore_previous. Last night the build and the upload both succeeded, the notification step inside upload failed, and the script restored the previous release over the new one. Explain what happened and rewrite the logic.
- What it tests
- Knowing that && and || group from the left with equal precedence, that the right side of || runs after any failure on the left, and writing the intent with if.
- First step
- Group the line the way Bash does, (build && upload) || restore_previous: upload returned non-zero because its last step failed, so the left side failed and the restore ran although the release was good.
- Follow-ups
-
- How would you make upload's status mean only "the files are uploaded"?
- Would set -e have stopped the restore?
- How would you test this script before the next deploy?
From the lesson Exit status, &&, || and command lists
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
You are writing a backup tool that other scripts and a scheduler will call. It can fail because the disk is full, the remote host is unreachable or the arguments are wrong. Which exit statuses would you use, and how would callers rely on them?
- What it tests
- Knowing the conventional and reserved statuses (0, 1, 2, 126, 127, 128 plus a signal), the 8-bit limit, and designing documented codes that callers can branch on.
- First step
- Keep 0 for success and 2 for wrong usage, the status Bash's own builtins return for incorrect usage, then give each failure its own small code below 126, such as 3 for disk full and 4 for unreachable, and document them in the usage text.
- Follow-ups
-
- Why not use 127 or 130 for one of these errors?
- What happens if the tool exits with 256?
- How should a caller act on each code?
From the lesson Exit status, &&, || and command lists
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Fresher to mid
A cleanup script has if [ -n $BACKUP_DIR ]; then rm -rf "$BACKUP_DIR"/old; else echo "no backup folder"; fi. On a machine where BACKUP_DIR was never set, it ran rm on /old instead of printing the message. Explain exactly why, and fix it.
- What it tests
- Knowing that an unquoted empty variable vanishes before [ runs, the one-argument rule of test, and the safe forms: quoting and a guard such as ${BACKUP_DIR:?}.
- First step
- Expand the line by hand with BACKUP_DIR empty: [ -n ] is left, a one-argument test that is true because "-n" is a non-empty string, so the then branch ran and "$BACKUP_DIR"/old became /old.
- Follow-ups
-
- Why did quoting only the rm argument not save the script?
- What would ShellCheck have said about the test?
- How would you make a missing BACKUP_DIR stop the script?
From the lesson test and [ ]: file, string and number checks
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A team moves an install script from #!/bin/bash to #!/bin/sh so that it runs in minimal containers whose sh is dash. Its tests include [ "$a" == "$b" ], [ -f "$f" -a -x "$f" ] and [[ $os == linux* ]]. What would you change, and how would you check the result?
- What it tests
- Knowing which test forms are Bash extensions, what POSIX.1-2024 removed from test, portable replacements such as case for patterns, and checking with dash itself and ShellCheck.
- First step
- Classify each form: == is a Bash extension that dash refuses, -a was removed from POSIX test, and [[ ]] does not exist in dash; each has a portable replacement, =, two tests joined by &&, and case for the pattern.
- Follow-ups
-
- Why is running the script under bash in tests not enough?
- Which ShellCheck warnings would point at the three lines?
- When is keeping #!/bin/bash the better decision?
From the lesson test and [ ]: file, string and number checks
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Fresher to mid
A log rotation script had if [[ $file == app-.log ]]. After a team rule to "quote everything" was applied, it became if [[ $file == "app-.log" ]], and since then no file is rotated. What happened, and what is the right way to quote here?
- What it tests
- Knowing that the right side of == in double brackets is a pattern, that quoting makes it literal, and when quotes are actually needed in [[ ]].
- First step
- Point out that the quotes turned the glob into the literal text app-*.log, which no real file name equals; inside [[ ]] the left side is never split, so the original line needed no quotes at all.
- Follow-ups
-
- How would you match a prefix stored in a variable?
- Would the same quoting rule apply to [ ]?
- How could a test have caught this before release?
From the lesson [[ ]]: patterns, regex and BASH_REMATCH
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A form handler validates a pincode with re='[0-9]{6}' and [[ $pin =~ $re ]]. Testers report that 4000012, 560001x and abc560001 are all accepted. Explain why, fix the check, and say what the check still cannot tell you.
- What it tests
- Knowing that =~ matches anywhere unless anchored, anchoring with ^ and $, testing edge cases, and the limits of a shape check against real data.
- First step
- Explain that an unanchored pattern only needs six digits somewhere in the string: 4000012 contains 400001 and abc560001 contains 560001. Anchor it as ^[0-9]{6}$ so the whole value must be six digits.
- Follow-ups
-
- Which inputs would you add to the tests, and why?
- Should the check be done in Bash at all?
- What does a shape check not tell you about a pincode?
From the lesson [[ ]]: patterns, regex and BASH_REMATCH
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Fresher to mid
A deploy job runs service.sh restat, a typo for restart. The script's case has branches for start, stop and restart only. It printed nothing, the job reported success, and the old version kept running for an hour. Explain what happened and fix the script.
- What it tests
- Knowing that a case with no matching pattern runs nothing and ends with status 0, and adding a default branch that prints the usage on standard error and exits with a documented failure status.
- First step
- Point out that no pattern matched restat, so no branch ran, and POSIX gives a case that matched nothing status 0; the script ended with 0 and the job saw success. Add a last *) branch that prints the usage to standard error and exits with 2.
- Follow-ups
-
- Why should the usage go to standard error in that branch?
- What status should --help return, and why is it different?
- How would you make the deploy job catch this kind of mistake?
From the lesson if, elif, else and case statements
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An upload handler sorts files with case: .gz) runs gunzip, .tar.gz) runs tar -xzf, and *) leaves the file alone. Users report that backup.tar.gz ends up as backup.tar, never unpacked. Explain the cause, fix it, and say how you would stop the same mistake coming back.
- What it tests
- Knowing that case tries patterns from the top and runs only the first match, ordering patterns from specific to general, and guarding the order with static checks and tests.
- First step
- Trace backup.tar.gz through the patterns in order: .gz already matches it, so the gunzip branch runs and case stops; the .tar.gz branch can never run for any name. Put .tar.gz above .gz.
- Follow-ups
-
- Which tool would have warned about this, and what does it say?
- Would ;;& be a good fix here?
- How would you test the order of the patterns?
From the lesson if, elif, else and case statements
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
All Bash & the POSIX Shell interview questions · The Bash & the POSIX Shell track