Shell & Bash Interview Questions and Answers

Scripting, pipes, permissions, process management and automation.

Practise 10 random 10 peer-reviewed questions
Shell & Bash Interview Syllabus & Preparation Strategy

Whether you are preparing for entry-level Shell & Bash interview questions for freshers or senior software engineer interview questions addressing concurrency, scalability, and system architecture, this track provides peer-reviewed model answers with syntax walkthroughs, edge cases, and practical interview tips.

1 What is the difference between single quotes and double quotes? Easy

Single quotes preserve everything literally, while double quotes allow variable expansion, command substitution and some escape sequences.

name="world"
echo 'hello $name'    # hello $name
echo "hello $name"    # hello world
echo "total: $(wc -l < file)"

The most important habit is to double-quote variable expansions such as "$var", "$@" and "$(cmd)" to prevent word splitting and glob expansion. An unquoted expansion containing spaces becomes several arguments:

files="a b c"
for f in $files; do echo "$f"; done    # three iterations
for f in "$files"; do echo "$f"; done  # one iteration

Inside double quotes, $, backticks, backslash and, interactively, ! are special. Single-quoted strings have no escapes at all, so including a single quote requires ending the string, escaping and reopening it: 'it'\''s'. The $'...' form enables escape sequences.

2 How do file permissions and chmod work? Easy

Every file has permissions for owner, group and others, each with read (4), write (2) and execute (1). chmod changes them in symbolic or octal form.

chmod 644 notes.txt     # rw- r-- r--
chmod 755 script.sh     # rwx r-x r-x
chmod u+x script.sh     # add execute for the owner
chmod g-w file          # remove write for the group

Directories need execute permission to enter or traverse them, and read permission to list names. Special bits include setuid, setgid and the sticky bit, as in 1777 on /tmp, which lets only the owner delete their own files.

chown user:group file changes ownership, and umask controls default permissions for new files. A common umask of 022 yields 644 files and 755 directories.

A script must be readable by the interpreter and executable, or you invoke it as bash script.sh. Follow least privilege and avoid 777.

3 What is a shebang and why does it matter? Medium

A shebang is the first line of a script, beginning with #!, that names the interpreter used when the file is executed directly.

#!/usr/bin/env bash

Using /usr/bin/env bash searches PATH for bash, which is more portable than hardcoding /bin/bash. The kernel reads the line when the file is executed, which also requires the execute bit. If you run bash script.sh instead, the shebang is ignored and treated as a comment.

Common choices are #!/bin/sh for POSIX portability, #!/usr/bin/env python3 and #!/usr/bin/env zsh. A wrong path produces a "bad interpreter" error. The line must be the very first bytes, with no leading blank line or byte order mark.

After the shebang, scripts commonly enable strict mode with set -euo pipefail, keeping in mind that POSIX sh does not support all bash options.

4 How do you make a Bash script fail fast and clean up with trap? Medium

Robust scripts fail fast and release resources.

#!/usr/bin/env bash
set -euo pipefail

cleanup() { rm -f "$tmp"; echo "cleaned" >&2; }

tmp=$(mktemp)
trap cleanup EXIT ERR INT TERM

false || echo "handled"
  • set -e exits when a command fails, but not inside if, while, || or && conditions.
  • set -u errors on unset variables; use ${var:-default} for optional values.
  • set -o pipefail makes a pipeline fail if any stage fails, not only the last.
  • trap 'cmd' EXIT always runs on exit, ERR fires on error, and INT or TERM handle signals. trap -p lists active traps.

Pitfalls: set -e is skipped in some subshell and function contexts, so check critical commands explicitly, and remember traps are reset in subshells. Always quote variables and prefer [[ ]] in bash.

5 How do pipes and redirection work? Medium

Every process has three standard streams: stdin (0), stdout (1) and stderr (2). Redirection connects them to files or other processes.

cmd > out.log          # stdout to file, truncate
cmd >> out.log         # append
cmd 2> err.log         # stderr only
cmd > all.log 2>&1     # both, order matters
cmd &> all.log         # bash shorthand
cmd < input.txt        # stdin from file
cmd | tee out.log      # pipe and also write a file

A pipe connects the stdout of the left command to the stdin of the right and runs both concurrently. The exit status of a pipeline is the last command's unless pipefail is set.

Order matters in > all.log 2>&1: the file descriptor 2 is pointed at wherever 1 currently points, so redirect stdout first. <<< is a here-string, <<EOF a here-document, and |& pipes both streams. Process substitution such as <(cmd) presents command output as a file.

6 How do you manage background processes and signals? Medium

Bash can start, inspect and signal processes. Append & to run a job in the background and $! holds its PID. wait blocks until it finishes.

sleep 30 &
pid=$!

kill -TERM "$pid"      # ask to stop, catchable
sleep 1
kill -KILL "$pid"      # forced, cannot be caught
wait "$pid" 2>/dev/null || true

jobs -l

Useful signals are SIGTERM for graceful shutdown, SIGINT from Ctrl-C, SIGHUP for reload or terminal close, SIGKILL for force and SIGSTOP/SIGCONT to pause and resume. kill -l lists signal names and numbers.

Trap signals for cleanup with trap 'echo bye; exit' TERM INT. pkill and pgrep match by name, while kill 0 signals the whole process group. Prefer tracking PIDs over killall, because name matching can hit unrelated processes, and never kill a PID you did not start.

7 How do variables, $?, $@ and $* behave? Medium

Shell variables hold strings and have no strict typing. $? is the exit status of the last command, where 0 means success.

greeting="hello"
echo "${greeting} world"

readonly PI=3.14
export PATH="$PATH:/opt/bin"

${var:-default} supplies a default without assigning, ${var:=default} assigns it, ${#var} is the length and local scopes a variable to a function.

For positional parameters, the quoting rules are crucial:

  • "$@" expands to separate, individually quoted arguments, which is correct for forwarding.
  • "$*" joins all arguments into a single string using the first character of IFS.
  • $# is the argument count, $0 the script name, $1 and onward the arguments, and shift drops the first.
for arg in "$@"; do echo "$arg"; done

Always prefer "$@". Use readonly for constants, and arrays where "${arr[@]}" is the analogue of "$@".

8 What are the pitfalls of command substitution? Medium

Command substitution captures the stdout of a command as a string. Use $(cmd) rather than backticks, which are deprecated and harder to nest.

today=$(date +%F)
count=$(wc -l < file)
files=$(find . -name '*.log')

Pitfalls to watch for:

  • Unquoted substitution undergoes word splitting and globbing, so rm $(cat list) breaks on filenames with spaces. Quoting helps only for a single value; for many values use a loop or an array.
  • Trailing newlines are stripped from the captured output.
  • The exit status of the command is not captured in the assignment, so if you need it, run the command first and capture $? immediately.
  • Command output used as a path or option must be validated, because it can be empty or contain unexpected characters.
while IFS= read -r line; do echo "$line"; done < list
mapfile -t lines < list        # bash 4+, preserves lines

Prefer mapfile, NUL-delimited tools and explicit validation.

9 When should you use find -exec versus xargs, and how do you handle odd filenames? Hard

Both run a command for many files, but they differ in safety and performance.

find . -name '*.tmp' -exec rm -- {} +      # batches, handles spaces
find . -name '*.tmp' -print0 | xargs -0 rm --

-exec cmd {} \; runs the command once per file. -exec cmd {} + batches as many files as the argument limit allows, which is much faster and still handles spaces correctly.

xargs reads items from stdin and builds commands. By default it splits on whitespace and mishandles quotes and spaces, so pair find -print0 with xargs -0 for NUL-delimited input. Useful flags are -n1 to limit files per invocation, -P4 for parallelism and -I{} for substitution.

The main advantage of xargs is parallelism; -exec ... + avoids an extra process and is safer by default. Filenames can even contain newlines, so preview destructive commands with echo before running them.

10 How would you write a robust, idempotent automation script? Hard

A production script should be safe to re-run, fail clearly and clean up after itself.

#!/usr/bin/env bash
set -euo pipefail

workdir=$(mktemp -d)
cleanup() { rm -rf "$workdir"; }
trap cleanup EXIT ERR INT TERM

log() { printf '%s %s\n' "$(date -Is)" "$*" >&2; }

main() {
    if [[ $EUID -ne 0 ]]; then
        log "must run as root"
        exit 1
    fi
    mkdir -p /etc/myapp
    install -m 0644 config.toml /etc/myapp/config.toml
    systemctl is-active --quiet myapp || systemctl start myapp
    log "done"
}

main "$@"

Practices that matter: quote expansions, validate inputs and check tools with command -v, use mktemp for temporary files, and make actions idempotent by creating only what is missing and using install for exact permissions. Log to stderr, return meaningful exit codes, avoid unchecked cd, and document dry-run options.

Frequently Asked Questions About Shell & Bash Interviews

What do hiring managers evaluate in Shell & Bash technical rounds?

Technical interviewers look for foundational fluency, idiomatic syntax, clarity when communicating complex logic, and awareness of performance trade-offs (e.g. memory footprint, render performance, and network latency) in production environments.

What are the best interview tips for practicing Shell & Bash questions?

Use active recall: summarize each answer in your own words before revealing the model solution. Focus on explaining why a certain approach is chosen rather than just memorizing code syntax.