Top 50 Bash and Shell Scripting Interview Questions 2026
Bash is the language nobody puts on their resume but everybody is expected to know. If you are interviewing for SRE, DevOps, platform, or any backend role that involves a runtime, expect to be dropped into a terminal. The interviewer is not testing whether you can write a 500-line bash framework. They are testing whether you can read someone else's grungy script and reason about what will go wrong.
Here are the 50 questions that come up most often, in the order an interviewer might escalate from "do you know the basics" up to "can you debug this live." After the 50 there are three bonus parts (questions 51-70) covering the two shapes interviewers actually use - "type a one-liner" versus "write me a script" - plus the live debugging scenarios and a quick-fire questions-and-answers round for the night before.
Practice alongside this post. The same ground is drilled as timed multiple-choice in the DevOps question bank and the Operating Systems question bank; keep the Unix essentials cheat sheet open while you work through the redirection and process questions, and the free daily challenge gives you one question a day with no account needed. If your loop covers more than the shell, the sibling posts are Top 50 Linux interview questions, Top 50 DevOps interview questions and Top 50 SRE interview questions.
Part 1: Fundamentals (1-12)
1. What is the difference between sh, bash, zsh, and dash?
sh is the POSIX shell standard. On most Linux distros, /bin/sh is a symlink to dash (Debian/Ubuntu) or bash (in POSIX mode). bash is the GNU Bourne-Again Shell with many extensions. zsh is interactive-friendly with extra features. Scripts targeting portability should use #!/bin/sh with POSIX-only features; scripts that need bashisms should explicitly #!/bin/bash.
2. What does the shebang line do?
#!/bin/bash tells the kernel which interpreter to use when executing the file. Without it, the script runs in whatever shell invoked it. #!/usr/bin/env bash is more portable because env finds bash on PATH (useful when bash lives in /usr/local/bin/ on macOS).
3. What is the difference between ', ", and backticks in bash?
- Single quotes
'...'- literal, no expansion of any kind. - Double quotes
"..."- variable expansion, command substitution, but no glob expansion. - Backticks
`...`- command substitution. Use$(...)instead because it nests cleanly.
4. What is $@ vs $*?
Both refer to all positional parameters. The difference shows up when quoted:
"$@"expands to"$1" "$2" "$3"(each argument quoted separately)."$*"expands to"$1 $2 $3"(one string).
Always prefer "$@". Forgetting this is the cause of many "spaces in filenames break my script" bugs.
5. What does set -e do? When can it bite you?
set -e causes the script to exit on any command failure. Bites you because:
- Pipelines: only the last command's exit matters unless you also
set -o pipefail. - Commands inside
if,&&,||, or!do not trigger exit. - Functions called inside
&&do not respectset -ein some bash versions.
The standard incantation for "strict mode" scripts: set -euo pipefail.
6. What does set -u do?
Treats undefined variables as errors. Forces you to be deliberate about variables. Use ${VAR:-default} when you genuinely want a fallback.
7. What is parameter expansion ${VAR:-default}?
If VAR is unset or empty, use default. Variants:
${VAR:-default}- use default if unset/empty (does not assign).${VAR:=default}- assign default if unset/empty.${VAR:?error}- exit with error if unset/empty.${VAR:+alt}- usealtif VAR is set.
8. How do you check if a variable is empty?
if [[ -z "$VAR" ]]; then
echo "empty"
fi
Or [[ -n "$VAR" ]] for non-empty. Use [[ ]] over [ ] in bash - it has saner quoting and supports pattern matching.
9. What is the difference between [, [[, and (( ))?
[ ... ]- POSIX test, also known astest. Works in any shell, but quoting is treacherous.[[ ... ]]- bash conditional, smarter parsing, supports&&,||,=~. Bash-only.(( ... ))- arithmetic context.(( x > 5 ))evaluates as a number.
10. How do you read user input?
read -r -p "Enter name: " name
-r prevents backslash from being interpreted as escape. Always use -r unless you have a specific reason not to.
11. What is command substitution?
files=$(ls *.txt)
The output of the inner command becomes the value. Always quote: "$(ls *.txt)" if you want to preserve newlines and spaces.
12. What does command || true do?
Forces a command to "succeed" so set -e does not exit the script. Useful when a command might fail for non-fatal reasons (e.g., grep returning nothing).
Part 2: I/O and Redirection (13-22)
13. Explain the three standard streams.
stdin(file descriptor 0) - input.stdout(file descriptor 1) - normal output.stderr(file descriptor 2) - errors and diagnostics.
14. How do you redirect stderr?
command 2> error.log # stderr to file
command 2>&1 # stderr merged into stdout
command > all.log 2>&1 # both to a file (order matters)
command &> all.log # bash shorthand for both
15. What is tee and why is it useful?
Reads stdin and writes to both stdout and one or more files.
command | tee output.log
command | tee -a output.log # append
command | sudo tee /etc/file # the standard "write to root file" trick
16. What is a pipe vs a redirect?
A pipe | connects one process's stdout to another process's stdin in memory. A redirect > connects to a file. > truncates by default; >> appends.
17. What is << (heredoc) and <<< (herestring)?
Heredoc passes a multi-line string as stdin:
cat <<EOF
Hello $USER
EOF
Use <<'EOF' (quoted delimiter) to disable variable expansion. Herestring passes a single line:
grep root <<< "$content"
18. What is /dev/null?
A bit-bucket. Reading returns EOF. Writing discards. command > /dev/null 2>&1 silences a command entirely.
19. What is process substitution <(...)?
Treats the output of a command as a temporary file:
diff <(sort file1) <(sort file2)
bash-only feature, very useful for diff and comparison workflows.
20. What is the difference between $(command) and $(< file)?
$(command) runs a command and captures stdout. $(< file) reads a file's contents into a variable - faster than $(cat file) because no fork.
21. How do you redirect into and out of a specific FD?
exec 3< input.txt # open FD 3 for reading
read -r line <&3
exec 3<&- # close FD 3
Useful for advanced scripts that need to read from multiple files concurrently.
22. What does command 1>&2 mean?
Send stdout (FD 1) to where stderr (FD 2) currently points. Often used in echo "Error: ..." 1>&2 to write error messages to stderr.
Part 3: Control Flow and Functions (23-32)
23. How do you write a function?
my_function() {
local arg="$1"
echo "Got: $arg"
}
my_function "hello"
Always declare locals with local to avoid leaking variables into the enclosing scope.
24. How do you return a value from a function?
return only sets an exit status (0-255). To return data, echo it and capture with command substitution:
get_user() {
echo "alice"
}
USER=$(get_user)
25. What is local and why does it matter?
Declares a variable scoped to the current function. Without it, variables leak out and cause cross-function bugs that are nightmarish to debug. Always use local.
26. How do you iterate over arguments?
for arg in "$@"; do
echo "Arg: $arg"
done
Quoted "$@" preserves arguments with spaces.
27. How do you read a file line-by-line?
while IFS= read -r line; do
echo "Line: $line"
done < file.txt
IFS= prevents leading/trailing whitespace stripping. -r prevents backslash escaping. Both matter for correctness.
28. What does IFS control?
Internal Field Separator. Determines how bash splits unquoted command output and the read command. Default is space-tab-newline. Set IFS=$'\n' to split only on newlines, or IFS=',' for CSV.
29. What is the difference between &&, ||, and ;?
cmd1 && cmd2- run cmd2 only if cmd1 succeeded.cmd1 || cmd2- run cmd2 only if cmd1 failed.cmd1 ; cmd2- run cmd2 regardless.
Common idiom: mkdir -p /path && cd /path - only cd if mkdir succeeded.
30. What is a case statement?
Pattern-matching alternative to long if-else chains:
case "$1" in
start) start_service ;;
stop) stop_service ;;
*) echo "Unknown: $1" ;;
esac
31. What does getopts do?
Parses command-line options:
while getopts "f:vh" opt; do
case $opt in
f) FILE="$OPTARG" ;;
v) VERBOSE=1 ;;
h) usage; exit 0 ;;
esac
done
For long options (--file), use getopt (not getopts) or write a manual parser.
32. How do you write an idempotent script?
Check before acting. Examples:
mkdir -pinstead ofmkdir.[[ -f file ]] || touch file.grep -q pattern file || echo pattern >> file.- Use proper config management (Ansible, etc.) for anything beyond trivial.
Part 4: Signals, Traps, and Background (33-40)
33. What is a trap and how do you use it?
Runs a command when a signal is received (or on exit):
cleanup() {
rm -f /tmp/myfile
}
trap cleanup EXIT
The EXIT pseudo-signal fires regardless of how the script exits.
34. How do you handle Ctrl-C cleanly in a script?
trap 'echo "Interrupted"; exit 130' INT
130 is the conventional exit code for SIGINT (128 + signal number).
35. What is nohup?
Runs a command immune to hangup (SIGHUP), so it survives terminal close. Output redirected to nohup.out by default. Modern alternative: systemd-run --user --scope, or just run it in tmux/screen.
36. What is the difference between & and disown?
& runs in the background but the process is still attached to the shell - it dies with the shell. disown removes the job from the shell's job table so it survives. nohup ... & is the classic combination.
37. How do you wait for background jobs to complete?
job1 &
job2 &
wait
wait blocks until all background jobs in the current shell finish. wait $! waits for the most recently launched. wait -n waits for any one to finish.
38. How do you kill a process by name?
pkill -f "my_script.sh"
# or:
ps -ef | grep my_script | grep -v grep | awk '{print $2}' | xargs kill
Be careful with pkill -f - it matches against the full command line and you can clobber unintended processes.
39. How do you check if a previous command succeeded?
$? is the exit code of the last command. Zero is success.
some_command
if [[ $? -eq 0 ]]; then
echo "ok"
fi
Or just use if some_command; then ....
40. What are PIPESTATUS and BASH_REMATCH?
PIPESTATUS is an array of exit codes from each command in the last pipeline. Useful when set -o pipefail is not enough. BASH_REMATCH holds capture groups from [[ $str =~ regex ]].
Part 5: Live Debugging and Performance (41-50)
41. Walk me through how you would debug a script that "stops working" silently.
Add set -x (trace) at the top, or run bash -x script.sh. Add PS4='+ ${BASH_SOURCE}:${LINENO}: ' to show file and line in trace output. Check return codes after every meaningful command. If the script is huge, instrument with echo "DEBUG: ..." 1>&2 at decision points.
42. A bash script is taking 30 seconds to run a simple loop. How do you investigate?
Look for:
- Subshells inside loops (
$(command)10,000 times = 10,000 forks). - External tool calls inside loops (
grep,sed,awkper iteration - batch them instead). - Network or file system calls without caching.
Profile with time and by adding date +%s.%N checkpoints.
43. How do you check for syntax errors without running the script?
bash -n script.sh
Pairs well with shellcheck script.sh for static analysis.
44. What is shellcheck and why should I use it?
A static analyzer that catches common bash bugs: missing quotes, unused variables, deprecated syntax, subtle issues with read, for, etc. Run it on every script before reviewing. Most editors have a plugin.
45. How do you handle large data in bash without crashing?
Use streams, not arrays. Pipe through awk, sort, cut instead of reading whole files into bash arrays. Bash is slow at iterating large arrays, but excellent at gluing fast tools together.
46. What is the difference between awk and sed for an interview question?
sed- stream editor for line-by-line transformations (substitute, delete, insert).awk- field-aware scripting language for tabular data, with state.
Rule of thumb: if the task fits in one regex substitution, use sed. If it involves columns, conditions, or aggregation, use awk.
47. Write a one-liner to find the largest 10 files in a directory tree.
find . -type f -exec du -h {} + | sort -rh | head -10
48. Write a one-liner to count occurrences of each unique line in a file.
sort file | uniq -c | sort -rn
49. Write a one-liner that fails loudly if a command produces unexpected output.
output=$(command)
[[ "$output" == "expected" ]] || { echo "Unexpected: $output" >&2; exit 1; }
50. When should you stop using bash and switch to Python (or Go)?
Roughly:
- 100 lines is your soft limit. Past that, the readability cost compounds.
- Anything with structured data (JSON, complex argument parsing, async) - bash will hurt.
- Anything that needs unit tests - bash testing exists (
bats) but Python is dramatically better. - Anything that needs to be cross-platform.
The right answer in interview: "I default to bash for glue and orchestration, Python for anything with logic, Go for anything that needs to be a real binary."
Bonus Part 6: Script vs One-Liner Questions (51-58)
Bash interview questions come in two shapes, and candidates lose points by answering one shape with the other. A one-liner question ("how would you find the ten most common IPs in this log?") is testing fluency: can you compose the coreutils without looking anything up. A script question ("write me something that does that for any log and any N") is testing structure: argument handling, error handling, exit codes, and whether the thing is safe to hand to a colleague. Read the prompt for the cue - "quickly", "off the top of your head", "in the terminal" mean one-liner; "write a script", "make it reusable", "how would you ship this" mean script.
51. How do you decide between a one-liner and a script?
A one-liner is right when it is run by a human, once, and the failure mode is "I look at the output and it is wrong." A script is right the moment any of these become true: it runs unattended (cron, CI, a systemd timer), it takes arguments from someone else, it deletes or overwrites anything, or you have typed it a third time. Say this out loud in the interview - the decision matters more than the syntax.
52. One-liner: the 10 most common client IPs in an access log.
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
sort before uniq -c is mandatory - uniq only collapses adjacent duplicates. sort -rn sorts numerically on the count. If the interviewer asks for percentages, that is the cue to switch to a single awk program with an associative array and an END block.
53. Now turn it into a script that takes a log path and N.
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "usage: $(basename "$0") <access.log> [N]" >&2
exit 2
}
[[ $# -ge 1 && $# -le 2 ]] || usage
log="$1"
n="${2:-10}"
[[ -r "$log" ]] || { echo "error: cannot read '$log'" >&2; exit 1; }
[[ "$n" =~ ^[0-9]+$ ]] || { echo "error: N must be a positive integer" >&2; exit 2; }
awk '{print $1}' "$log" | sort | uniq -c | sort -rn | head -n "$n"
What the interviewer is checking, in order: strict mode, a usage function that exits non-zero, argument count validation, that the file is readable before the pipeline runs, that N is validated rather than trusted, and that every variable is quoted. Exit code 2 for usage errors and 1 for runtime errors is the convention most CLI tools follow.
54. One-liner: rename every .jpeg in a directory to .jpg.
for f in *.jpeg; do mv -- "$f" "${f%.jpeg}.jpg"; done
${f%.jpeg} strips the shortest matching suffix. -- stops mv from treating a filename beginning with - as an option. The gotcha to mention: if the glob matches nothing, the loop runs once with the literal string *.jpeg. Guard it with shopt -s nullglob in a script. Do not reach for the rename command in an answer - it has two incompatible implementations (Perl and util-linux) with different syntax, and the interviewer may have the other one.
55. One-liner: files under /var/log modified in the last 24 hours and larger than 100 MB.
find /var/log -type f -mtime -1 -size +100M
-mtime -1 means "less than one day ago"; -mtime 1 means "between 24 and 48 hours ago", a classic trip-up. Add -exec ls -lh {} + if they want sizes, and -print0 | xargs -0 if the output feeds another command, so filenames with spaces or newlines survive.
56. Run a command on every host in a file, in parallel, and tell me which ones failed.
One-liner shape:
xargs -a hosts.txt -P 10 -I{} sh -c 'ssh -o BatchMode=yes -o ConnectTimeout=5 {} uptime >/dev/null 2>&1 || echo "FAILED {}"'
Script shape: loop over the hosts with ssh ... &, collect the PIDs, wait "$pid" on each and record the exit status against the hostname, then print a summary and exit non-zero if any failed. BatchMode=yes stops ssh from hanging on a password prompt when a key is missing, which is the single most common reason a fleet script "stops working" halfway through. ConnectTimeout bounds the cost of a dead host.
57. Write a function that retries a command with exponential backoff.
retry() {
local -r max_attempts="$1"; shift
local attempt=1 delay=1
until "$@"; do
if (( attempt >= max_attempts )); then
echo "retry: '$*' failed after $attempt attempts" >&2
return 1
fi
echo "retry: attempt $attempt failed, sleeping ${delay}s" >&2
sleep "$delay"
(( attempt++, delay *= 2 ))
done
}
retry 5 curl -sf https://example.com/health
Points to land: "$@" passes the command through with its arguments intact, until loops while the command fails, the backoff doubles, and the function returns a real exit status so callers can retry 5 ... || exit 1. Mention adding jitter (delay + RANDOM % delay) if the interviewer works anywhere with a thundering-herd story.
58. Check whether a TCP port is open, without nc or nmap.
timeout 2 bash -c ': </dev/tcp/example.com/443' && echo open || echo closed
Bash treats /dev/tcp/HOST/PORT as a pseudo-device that opens a TCP connection when redirected. timeout bounds the connect. This is a bash feature, not a kernel one - it does not work under sh or dash, which is exactly the kind of portability detail the shebang question (question 2) was setting up.
Bonus Part 7: Live Debugging Scenarios (59-65)
The highest-signal bash question is not "what does $@ do" - it is a broken script on a shared screen and the words "this is failing in production, what's wrong?" Each scenario below is one that appears in real interviews. Practice reading them cold and naming the bug before scrolling to the fix.
59. This loop breaks on some filenames. Why?
for f in $(ls *.log); do gzip $f; done
Two bugs. The $(ls ...) output is word-split on whitespace, so error 2026.log becomes two loop iterations, and the unquoted $f splits again. Never parse ls. The glob is already a list:
for f in *.log; do gzip -- "$f"; done
60. This errors with [: -gt: unary operator expected.
count=$(grep -c ERROR app.log)
if [ $count -gt 5 ]; then alert; fi
When grep finds nothing on a missing file, count is empty and the test becomes [ -gt 5 ]. Quote it ([ "$count" -gt 5 ]) so the empty string is still an operand, or better, use [[ ]], which does not word-split. Also note grep -c exits 1 when the count is zero, which under set -e would have killed the script one line earlier - the two bugs interact.
61. This prints an empty total. Why?
total=0
cat numbers.txt | while read -r n; do total=$((total + n)); done
echo "$total"
Every stage of a pipeline runs in a subshell, so the while loop's total is a copy that dies with the subshell. Redirect instead of piping:
while read -r n; do total=$((total + n)); done < numbers.txt
shopt -s lastpipe (with job control off) is the other fix; the redirect is the one to give in an interview because it works everywhere.
62. set -e is on, a command fails, and the script keeps going. How?
Three common ways:
local result=$(failing_command) # exit status of 'local', not the command
failing_command | tee log.txt # exit status of tee, without pipefail
if failing_command; then ... # failures inside 'if' are exempt by design
The first is the subtle one: local (and export, and declare) is itself a command that succeeds, so it masks the substitution's status. Declare on one line and assign on the next. The second is fixed by set -o pipefail or by checking PIPESTATUS[0]. The third is not a bug, but candidates who think set -e is a safety net rather than a heuristic will be surprised by it.
63. It works when I run it by hand and fails under cron.
The checklist, in the order you should say it:
- PATH. Cron's environment is nearly empty;
aws,kubectl,jqlive in directories cron does not search. Use absolute paths or setPATH=at the top of the crontab. - Working directory. Cron runs from
$HOME. Relative paths in the script point somewhere else.cd "$(dirname "$0")"or use absolute paths. - Shell. Cron runs
/bin/shunlessSHELL=/bin/bashis set, so bashisms fail with confusing errors. - No terminal. Anything that prompts hangs; anything that colours output may misbehave.
sshneedsBatchMode=yes. %in the crontab line is a newline to cron. Escape it as\%.- Where did the error go? Cron mails stderr to the user, which nobody reads. Redirect:
>> /var/log/job.log 2>&1.
64. This script hangs after the first host.
while read -r host; do
ssh "$host" 'uptime'
done < hosts.txt
ssh inherits the loop's stdin, which is hosts.txt, and reads the rest of the file as input for the remote command. Use ssh -n (redirects stdin from /dev/null) or ssh "$host" 'uptime' </dev/null. The same bug appears with ffmpeg, mysql and anything else that reads stdin when it is not a terminal.
65. What does this do when BUILD_DIR is unset?
rm -rf "$BUILD_DIR/"
rm -rf /. Modern coreutils refuse the bare root with --preserve-root, but "$BUILD_DIR/bin" becomes /bin, which is not protected. The fixes stack: set -u so an unset variable is fatal, ${BUILD_DIR:?BUILD_DIR must be set} so the error names the variable, and never build a deletion path by concatenating a variable with a literal without checking the variable is non-empty and is a directory you expect ([[ -d "$BUILD_DIR" && "$BUILD_DIR" == /tmp/build-* ]]).
Bonus Part 8: Shell Scripting Questions for Linux and DevOps Roles (66-70)
These are the questions that separate "knows bash" from "has run bash in production." They come up in Linux administrator, DevOps and platform loops far more than in pure software engineering ones.
66. What makes a script safe to run unattended from cron or CI?
- Strict mode (
set -euo pipefail) and atrap ... EXITthat cleans up temp files. - Absolute paths and an explicit
PATH. - A lock so two runs cannot overlap (next question).
- Logging with timestamps to a file, stderr for errors, and an exit code the scheduler can act on.
- Idempotency (question 32) - a rerun after a half-failure must be safe.
- No interactive prompts, no reliance on a TTY, no colour codes unless
[[ -t 1 ]]. - Secrets read from the environment or a
0600file, never from arguments (they show up inps).
67. How do you stop two copies of a script running at once?
exec 9>/var/lock/myjob.lock
flock -n 9 || { echo "already running" >&2; exit 0; }
# ... rest of the script; the lock releases when FD 9 closes on exit
flock on a file descriptor is atomic and releases itself when the process dies, unlike a PID file, which goes stale when the script is killed. -n fails fast; drop it to wait. Exiting 0 on "already running" is deliberate for cron so the overlap is not reported as a failure.
68. How do you parse JSON in bash?
You do not - you hand it to jq:
instance_id=$(aws ec2 describe-instances --filters Name=tag:Name,Values=web \
| jq -r '.Reservations[].Instances[].InstanceId')
-r outputs raw strings without quotes. The anti-pattern the interviewer is fishing for is grep/sed/cut on JSON, which breaks the first time the field order changes or a value contains a comma. If jq is genuinely unavailable, python3 -c 'import json,sys; ...' is on every Linux box; a regex is never the answer.
69. Write a wait-for-dependency loop for a container entrypoint.
#!/usr/bin/env bash
set -euo pipefail
deadline=$(( SECONDS + 60 ))
until curl -sf "http://db-proxy:8080/health" >/dev/null; do
if (( SECONDS >= deadline )); then
echo "dependency not ready after 60s" >&2
exit 1
fi
sleep 2
done
exec "$@"
SECONDS is a bash builtin that counts seconds since the shell started, which makes a deadline trivial. The exec "$@" at the end replaces the shell with the real process so it becomes PID 1 and receives SIGTERM directly - forgetting exec is why containers take ten seconds to stop.
70. How do you handle secrets in a shell script?
- Never pass them as command-line arguments:
ps -efshows every argument to every user on the host. - Read them from an environment variable or a file with
0600permissions, or from a secrets manager CLI at runtime. - Turn off tracing around them:
set +xbefore,set -xafter, or the secret lands in your CI log. - Prompt with
read -rsif a human must type one, so it is not echoed. - Do not
echothem into a heredoc that becomes a temp file without atrapthat shreds it. - Know that
historyrecords interactive commands;HISTCONTROL=ignorespaceand a leading space keep a one-off out of it.
Quick-Fire: Bash Scripting Interview Questions and Answers
The rapid round. Interviewers use these in the first five minutes to calibrate how deep to go, so have a one-sentence answer for each.
$0,$1,$#,$?,$$,$!- script name, first argument, argument count, last exit status, current PID, PID of the last background job.source script.shvs./script.shvsexec script.sh- run in the current shell (variables persist), run in a child process (nothing persists), replace the current shell with the script (no return).- What does
exportdo? - marks a variable for inheritance by child processes. Unexported variables are invisible to anything you launch. > file 2>&1vs2>&1 > file- the first sends both streams to the file; the second sends stderr to the original stdout (the terminal) and only stdout to the file. Redirections apply left to right.$(( ))vsexprvslet-$(( ))is the modern arithmetic expansion and the only one you should write;exprforks a process;letis a bash builtin with awkward quoting.- What does
shiftdo? - drops$1and renumbers the rest. The standard way to walk through arguments in a manual option parser. - Arrays -
arr=(a b c),"${arr[@]}"for all elements,${#arr[@]}for the count,declare -A mapfor an associative array. Bash arrays are not exportable to child processes. find ... -print0 | xargs -0- NUL-delimits filenames so spaces and newlines in names cannot split them. The only fully safe way to feedfindoutput into another command.- Exit codes - 0 success, 1 general error, 2 misuse of a builtin, 126 not executable, 127 command not found, 128+N killed by signal N (130 for Ctrl-C, 137 for
kill -9). typevswhich-typeis a builtin that also reports aliases, functions and builtins;whichis an external command that only searchesPATHand misses all three.env -i- runs a command with an empty environment; the fastest way to reproduce a "works for me, fails in cron" bug.trap ... ERR- runs a handler whenever a command fails (under the same rules asset -e). Pair it with$LINENOand$BASH_COMMANDto print exactly what failed and where.${var,,}and${var^^}- lowercase and uppercase a string without forkingtr. Bash 4+.readonly/declare -r- make a variable immutable; assigning to it is an error, which catches accidental overwrites of configuration.mktemp- creates a unique temporary file or directory (mktemp -d) safely. Never build temp paths from$$by hand.command -v foo- the portable way to test whether a command exists.if command -v jq >/dev/null; then ....
How to Practice for a Bash Interview
The same advice applies as with Linux questions: do not memorize. Do.
- Pick five questions a day and type them into a real terminal, even when you "already know" the answer. Fluency is what the one-liner round measures, and fluency comes from the fingers.
- Break the scenarios in Part 7 yourself. Copy each buggy snippet into a file, run it, watch it fail, then fix it. Seeing
[: -gt: unary operator expectedonce in your own terminal beats reading about it five times. - Build one real automation script per week. A log rotator, a deploy wrapper, a backup with retention, a fleet health check. Give it a
usage, strict mode, a lock and a trap. That is the script shape from question 53, and after four weeks it is muscle memory. - Run
shellcheckon everything you write and read every suggestion. Most of Part 7 is ashellcheckwarning you learned to ignore. - Explain out loud as you type. The live debugging round is as much about narrating your reasoning as it is about the fix. "Every stage of a pipeline is a subshell, so the variable is a copy" is the sentence that gets you the point.
- Timebox it. Ten minutes per scenario. Interviewers rarely give you longer, and the skill of saying "I would check X, then Y" when you are stuck is worth practising on its own.
The shell is muscle memory. You build it by doing.
Keep going
- Drill it under pressure: the DevOps and Operating Systems question banks cover shell scripting, processes and signals as timed multiple-choice, and the free daily challenge gives you one a day with no account.
- Keep the references open: the Unix essentials cheat sheet for the redirection and process material, the Linux performance essentials cheat sheet for the "why is this slow" scenarios, and the regex essentials cheat sheet for everything you feed to
grep,sedand=~. - Write code, not just shell: when the loop switches from the terminal to an editor, our coding challenges run your solution against real test cases in the browser.
- Round out the loop: Top 50 Linux interview questions, Top 50 DevOps interview questions, Top 50 SRE interview questions, Top 50 Docker interview questions and, if the role is a JVM backend with an on-call rotation, Top 50 Java interview questions. For the round itself, the live debugging interview round explains what interviewers are scoring when they hand you a broken script.
- Practise the follow-ups: the chat-based AI mock interview probes your reasoning with the kind of "and what if the file has spaces in its name?" follow-ups a real shell round runs on.
#bash #shell #scripting #interviews #devops #sre #career