Placement Training • 2026-10-31 • 28 min read

Top 25 Linux & Bash Shell Scripting Interview Questions Asked by Top Tech Companies in 2026

Top 25 Linux & Bash Shell Scripting Interview Questions Asked by Top Tech Companies in 2026

Section 1: Architecture, Shebangs & Execution Mechanics (Questions 1 to 5)

Question 1: What is the exact technical difference between #!/bin/bash and #!/usr/bin/env bash in a script shebang, and which should you use in production?

• Explanation: The shebang (#!) tells the Linux kernel program loader (execve) which interpreter to execute to parse the subsequent lines of the script. The line #!/bin/bash hardcodes the absolute binary path. While /bin/bash is conventional on Debian and RHEL systems, other environments—such as FreeBSD, OpenBSD, macOS, or specialized minimal Alpine Docker containers—may store Bash in /usr/local/bin/bash or /usr/bin/bash. If the hardcoded path does not exist, the kernel throws exec format error or bad interpreter: No such file or directory.

• The Best Practice: Using #!/usr/bin/env bash delegates binary discovery to the env binary, which searches the user's current environment PATH variable to find the first matching executable. This provides absolute cross-platform portability across differing operating system layouts and virtual environments.

Question 2: What is the difference between source ./script.sh (or . ./script.sh) versus ./script.sh?

• Explanation: When executing ./script.sh, the kernel spawns a distinct child process (subshell). Any environment variables created, modified, or exported inside the subshell exist solely within that child process's memory space and vanish the moment the script exits. Conversely, source ./script.sh reads and executes the commands inside the current active shell process. Any exported variables, aliases, or directory changes (cd) persist permanently in the calling shell environment. This is why virtual environment activations (source venv/bin/activate) mandate sourcing rather than direct execution.

**Question 3: Explain the difference between * and @ when enclosed in double quotes.**

• Explanation: Both * and @ represent all positional parameters passed to a script. However, when wrapped in double quotes:

• "" expands into a single concatenated string, where each argument is delimited by the first character of the IFS (Internal Field Separator) variable (defaulting to a space). For example, if 1='alpha' and 2='beta gamma', "" becomes "alpha beta gamma".

• "@" expands into separate, individually quoted strings: "1" "2" "3".... For the same parameters, "@" becomes "alpha" "beta gamma". In production scripts, you should almost always use "@" when looping over arguments to prevent spaces within arguments from being incorrectly fragmented by word splitting.

Question 4: What is the difference between single brackets [ ... ] and double brackets [[ ... ]] in Bash conditionals?

• Explanation: [ ... ] is POSIX-compliant and is actually an alias for the external binary/built-in command test. Because it behaves like a standard command, variables inside [ ... ] must be rigorously quoted to avoid syntax crashes caused by word splitting or empty strings (e.g., [ foo = "bar" ] fails with unary operator expected if foo is empty).

• [[ ... ]] is an extended Bash keyword that bypasses standard word splitting and pathname expansion. Furthermore, [[ ... ]] natively supports regular expression matching via the =~ operator (e.g., [[ email =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,} ]]) and logical operators (&&, ||) without requiring separate -a or -o flags.

Question 5: What does the variable $? represent, and why can checking it multiple times introduce race conditions or logical bugs?

• Explanation: $? holds the decimal exit status of the most recently executed foreground pipeline (0 indicates success; any integer between 1 and 255 indicates an error). The common bug occurs when an engineer writes:

command_a
if [ ? -ne 0 ]; then echo "Failed with: ?"; fi
In this example, the second ? inside the echo statement does not report the exit code of command_a; it reports the exit code of the [ (test) command itself! To avoid this, you must immediately cache the exit code into a local variable: STATUS=?.

  • Use #!/usr/bin/env bash for maximum portability across Linux distros, macOS, and containers.
  • source runs code in the current shell; ./script.sh spawns an isolated child subshell.
  • Always quote "$@" to preserve arguments containing spaces during loop iterations.
  • Prefer double brackets [[ ... ]] for robust condition checking and native regex support.
  • Always cache $? immediately if you need to reference the exit code more than once.

Section 2: Production Resilience, Error Handling & Signals (Questions 6 to 10)

Question 6: What does the standard defensive directive set -euo pipefail do, and why is it mandatory in enterprise production scripts?

• Explanation: By default, Bash is notoriously forgiving: it will happily continue executing subsequent commands even if an earlier command threw a fatal error, and it will silently treat uninitialized variables as empty strings. Adding set -euo pipefail at the top of a script enforces rigorous production safety:

1. set -e (errexit): Instructs Bash to exit immediately if any command returns a non-zero exit status, stopping error propagation.

2. set -u (nounset): Treats references to unset or uninitialized variables as fatal errors, instantly preventing catastrophic bugs like rm -rf /tmp/$UNSET_VAR/ resolving to rm -rf /tmp//.

3. set -o pipefail: In a pipeline like curl -s http://bad-url | grep 'token' | jq ., standard Bash only checks the exit status of the last command (jq). Even if curl failed completely with a 404/500 network error, the pipeline would return 0 if jq succeeded on empty input. pipefail ensures that if any command in the pipeline fails, the exit code of the entire pipeline reflects the failure.

Question 7: How do you implement robust, automated resource cleanup using the trap command when a script crashes or receives an interrupt signal?

• Explanation: In automated CI/CD pipelines and backup routines, scripts frequently create temporary directories (mktemp -d), lock files (/var/run/app.lock), or background worker processes. If an engineer cancels the script via Ctrl+C (SIGINT) or Kubernetes terminates the pod (SIGTERM), unhandled scripts leave orphaned lock files and stale disk usage. The trap command intercepts signals and guarantees execution of cleanup functions upon exit:

``bash
#!/usr/bin/env bash
set -euo pipefail
SCRATCH_DIR=(mktemp -d)
cleanup() {
echo 'Executing cleanup routine...'
rm -rf "
SCRATCH_DIR"
rm -f /tmp/backup.lock
}
trap cleanup EXIT SIGINT SIGTERM
`
Because
EXIT is a pseudo-signal in Bash, the cleanup` function will execute regardless of whether the script finishes cleanly, encounters a syntax crash, or is killed by an interrupt.

Question 8: How do you prevent multiple concurrent instances of the same Bash script from running simultaneously (Process Mutex / Locking)?

• Explanation: In legacy scripts, developers created touch files like /tmp/script.lock and deleted them at the end. This is fragile: if the server reboots or the process is killed via SIGKILL (kill -9), the file remains forever, permanently deadlocking future cron runs. The modern, atomic standard is to utilize flock (file lock based on kernel-level advisory locks):

``bash
exec 200>/var/lock/my_cron_job.lock || exit 1
flock -n 200 || { echo 'Error: Job already running. Aborting.' >&2; exit 1; }
# Critical section executes safely here
``
Because kernel file locks are automatically released when the file descriptor closes or the process terminates, deadlock is physically impossible.

Question 9: What is the difference between SIGTERM (signal 15) and SIGKILL (signal 9), and why should scripts avoid using kill -9 by default?

• Explanation: SIGTERM is the standard termination request sent by operating systems and container runtimes (like Docker and Kubernetes). It can be caught, handled, or blocked by the target application, allowing the process to gracefully flush database buffers, close network sockets, and complete in-flight transactions. Conversely, SIGKILL cannot be caught or handled by the process—the Linux kernel immediately deallocates the process memory. Resorting immediately to kill -9 risks corrupting persistent database files and leaving external resources in undefined states.

Question 10: How do you implement retry logic with exponential backoff in Bash for unstable network operations?

• Explanation: Production scripts calling third-party APIs or pulling remote assets must handle transient network drops gracefully. Interviewers love seeing clean algorithmic loops in Bash:

``bash
retry_with_backoff() {
local max_attempts=5
local timeout=2
local attempt=1
until "@"; do
if (( attempt >= max_attempts )); then
echo "Command failed after
max_attempts attempts." >&2
return 1
fi
echo "Attempt attempt failed! Retrying in {timeout}s..."
sleep "$timeout"
(( attempt++ ))
(( timeout *= 2 ))
done
}
# Usage: retry_with_backoff curl -f https://api.enterprise.com/health
``

  • Enforce set -euo pipefail across all production scripts to prevent silent failures and unbound variables.
  • Use trap cleanup EXIT SIGINT SIGTERM to guarantee deletion of temp files and lock releases.
  • Implement atomic process mutexes using flock rather than fragile manual touch files.
  • Never use kill -9 (SIGKILL) when kill -15 (SIGTERM) allows clean buffer flushes.
  • Implement exponential backoff algorithms for network calls to ensure enterprise-grade resilience.

Section 3: Process Management, Memory & Kernel Performance (Questions 11 to 15)

Question 11: What is the difference between a Zombie Process and an Orphan Process, and how do you resolve each?

• Explanation:

• Zombie Process (Z state in top / ps): A zombie is a process that has completed execution via exit(), but its parent process has not yet read its exit status via the wait() system call. The zombie process consumes zero CPU and zero memory, but it occupies a slot in the operating system's finite Process ID (PID) table. If zombie processes accumulate, they exhaust the system PID pool, preventing new processes from spawning. You cannot kill a zombie with kill -9 because it is already dead! To resolve it, you must kill or signal the parent process to reap its child.

• Orphan Process: An orphan is a running child process whose parent died or terminated before the child finished. The Linux kernel handles orphans gracefully by immediately re-parenting them to PID 1 (systemd or init), which adopts the child and reaps its exit code when it terminates.

Question 12: How do you troubleshoot high System Load Average when CPU utilization is near zero percent?

• Explanation: This is a classic Senior SysAdmin interview scenario. Load average (reported by uptime or top) represents the average number of threads that are either in a Runnable state (R) using/waiting for CPU, or in an Uninterruptible Sleep state (D) waiting for I/O. If CPU utilization is low (e.g., 5%) but the 1-minute load average is 45 on an 8-core machine, the bottleneck is almost certainly Disk I/O Wait (iowait) or Network Filesystem (NFS) blocking. To troubleshoot: inspect the %wa metric in top, run iostat -xz 1 to locate saturating disk devices (%util at 100%), and use pidstat -d 1 to identify the specific processes generating excessive read/write operations.

Question 13: Explain how the Linux OOM (Out-Of-Memory) Killer works and how to protect critical daemons from termination.

• Explanation: Linux allows memory overcommit (vm.overcommit_memory), allocating more virtual memory than physically exists based on the assumption that processes rarely use their full allocation simultaneously. When physical RAM and swap space become exhausted, the kernel invokes the Out-Of-Memory (OOM) Killer to terminate processes and salvage the operating system from a kernel panic. The kernel calculates an oom_score (0 to 1000) for every process based on memory usage percentage and runtime. To protect critical daemons (like database engines or sshd), an engineer adjusts the /proc/[pid]/oom_score_adj value. Setting this value to -1000 completely immunizes the target process from being terminated by the OOM Killer.

Question 14: What is the difference between Hard Links and Soft (Symbolic) Links at the Inode layer?

• Explanation:

• Hard Link: A hard link is an additional directory entry pointing directly to the exact same underlying filesystem Inode number. Hard links share the identical file permissions, ownership, and data blocks. If you delete the original file name, the data remains intact until all hard link references reach an Inode link count of 0. Hard links cannot span across different disk partitions or filesystems, nor can they link to directories.

• Soft (Symlink) Link: A symlink is an independent file with its own distinct Inode number whose data block contains the text string of the target path. If the target file is deleted or renamed, the symlink becomes a broken dangling pointer. Symlinks can span across different filesystems and can link to directories.

Question 15: How does Linux manage file descriptors, and how do you diagnose 'Too many open files' errors?

• Explanation: Everything in Linux is treated as a stream of bytes accessible via a File Descriptor (FD)—including files, network sockets, pipes, and devices. When an application exhausts its allocated FD quota, the kernel throws java.io.IOException: Too many open files or socket: too many open files. To diagnose: inspect the active open files per process using lsof -p | wc -l, check the system-wide limit in /proc/sys/fs/file-max, and adjust the per-user and per-process limits in /etc/security/limits.conf (nofile soft and hard limits) or systemd service units (LimitNOFILE=65536).

  • Zombies occupy PID slots without memory; clear them by signaling the parent process.
  • High load with low CPU indicates Disk I/O bottlenecks (D state processes); audit with iostat -xz 1.
  • The OOM Killer terminates memory hogs; protect critical services by setting oom_score_adj to -1000.
  • Hard links share the identical Inode; soft links are pointer files that break if the target path moves.
  • Diagnose file descriptor limits using lsof and configure production quotas via LimitNOFILE.

Section 4: High-Performance Text Processing & Log Parsing (Questions 16 to 20)

Question 16: You have a 25 GB Nginx access log file. How do you extract the top 10 unique IP addresses generating 5xx server errors in the fastest possible time?

• Explanation: In an interview, writing an inefficient Bash while loop that reads line-by-line in shell memory is an immediate red flag—it will take hours to process 25 GB. The high-performance approach leverages compiled C utilities (awk, sort, uniq):

``bash
LC_ALL=C awk '9 ~ /^5/ { print 1 }' /var/log/nginx/access.log | sort -S 2G | uniq -c | sort -rn -S 2G | head -n 10
`
• Performance Optimization Tip: Setting
LC_ALL=C forces byte-level comparisons rather than UTF-8 multi-byte character sorting, increasing processing throughput by up to 400%. Supplying -S 2G allocates dedicated buffer memory to sort`, preventing expensive disk paging during sorting runs.

Question 17: What is the fundamental difference in purpose between grep, sed, and awk?

• Explanation:

• grep (Global Regular Expression Print): Fast, stream-oriented search and filtering. Use grep when you simply need to identify or isolate lines matching a specific pattern without altering the text.

• sed (Stream Editor): Lightweight, non-interactive text transformation. Use sed for pattern substitution, deleting specific line numbers, or regex-based in-place file modifications (sed -i 's/foo/bar/g' config.env).

• awk (Aho, Weinberger, and Kernighan): A complete, Turing-complete pattern-scanning and data processing programming language. Use awk when you need column-aware data extraction, mathematical aggregations (sums, averages), multi-field relational filtering, and formatted report generation.

Question 18: How do you safely find and delete log files older than 30 days without risking command-injection or argument-list-too-long errors?

• Explanation: A naive approach like rm -rf $(find /logs -name '*.log' -mtime +30) fails catastrophically if millions of files match (triggering Argument list too long), or if filenames contain spaces and special characters. The enterprise standard is:

``bash
find /var/log/app -type f -name '.log' -mtime +30 -print0 | xargs -0 -r -P 4 rm -f
`
•
Why this is bulletproof:* -print0 delimits filenames with null bytes (\0), completely neutralizing malicious or irregular characters. xargs -0 safely reads null-separated streams, -r prevents running rm if the output is empty, and -P 4` parallelizes deletion across 4 worker threads for maximum disk efficiency.

Question 19: Explain the difference between standard output (stdout), standard error (stderr), and how to redirect both to the same file.

• Explanation: Linux binds three standard POSIX I/O streams to every executing process:

• File Descriptor 0 (stdin): Standard Input (keyboard or upstream pipe).

• File Descriptor 1 (stdout): Standard Output (normal output stream).

• File Descriptor 2 (stderr): Standard Error (unbuffered diagnostic and error stream).

To redirect both streams to a log file, the classic syntax is command > output.log 2>&1 (meaning: redirect stdout to output.log, then redirect stderr file descriptor 2 to wherever file descriptor 1 is currently pointing). In modern Bash (version 4.0+), you can utilize the concise syntax: command &> output.log.

Question 20: How do you replace all occurrences of a database connection string in a configuration file using sed when the string itself contains slashes?

• Explanation: Standard sed substitution uses forward slashes: sed 's/old/new/g'. When the string contains directory paths or URLs (e.g., postgresql://user:pass@host:5432/db), escaping every single slash (/) creates illegible 'leaning toothpick syndrome'. In sed, any character following the s command acts as the delimiter. You can cleanly use pipes, hashes, or colons:

sed -i 's|postgresql://old_host:5432/db|postgresql://new_host:5432/db|g' app.conf

  • Use LC_ALL=C awk for parsing massive multi-gigabyte log streams with maximum memory throughput.
  • Understand tool boundaries: grep filters, sed transforms, and awk processes structured columns.
  • Always combine find -print0 with xargs -0 to eliminate argument overflow and space-delimited parsing bugs.
  • Redirect both stdout and stderr cleanly using &> output.log in modern Bash environments.
  • Use alternative delimiters like s|old|new|g in sed when manipulating paths and connection URLs.

Section 5: Networking, Security & Cloud Automation (Questions 21 to 25)

Question 21: How do you check which process is listening on port 8080 without installing external third-party software?

• Explanation: On modern Linux systems (utilizing iproute2), you should use the ss (socket statistics) command, which directly queries kernel socket tables significantly faster than the deprecated netstat utility:

ss -tulpn | grep ':8080'
(Flags: -t TCP sockets, -u UDP sockets, -l listening sockets, -p process ID/name, -n numeric ports without slow DNS resolution).
Alternatively, you can inspect the filesystem directly via lsof -i :8080 or fuser 8080/tcp.

Question 22: What is the difference between setting permissions via chmod 755 vs chmod +x?

• Explanation: chmod 755 explicitly sets the octal permission bits for all three permission tiers: Owner gets 7 (rwx), Group gets 5 (r-x), and Others get 5 (r-x), wiping out any pre-existing permissions or setuid bits. Conversely, chmod +x uses symbolic notation to grant executable permission relative to the system umask across tiers without overriding existing read/write bits. In automated scripting, prefer explicit octal modes or targeted symbolic directives (e.g., chmod u+x to grant execution rights solely to the file owner).

Question 23: How do you establish passwordless, automated SSH communication between two Linux servers securely?

• Explanation:

1. Generate an enterprise-grade elliptic curve key pair on the source server: ssh-keygen -t ed25519 -C 'ci-cd-runner' -f ~/.ssh/id_ed25519 (Ed25519 provides superior cryptographic strength and faster handshakes than legacy 2048-bit RSA keys).

2. Copy the public key to the target server's authorized list: ssh-copy-id -i ~/.ssh/id_ed25519.pub user@remote-host.

3. Verify file permissions on the target server (strict POSIX permissions are mandatory; if permissions are too loose, the SSH daemon will refuse authentication): ~/.ssh directory must be chmod 700, and authorized_keys file must be chmod 600.

Question 24: What is the purpose of the Linux /proc and /sys virtual filesystems?

• Explanation: Neither /proc nor /sys consume real storage space on physical disk drives; they are pseudo-filesystems generated dynamically by the Linux kernel in RAM:

• /proc (Process Information Pseudo-file System): Exposes internal kernel data structures and running process states. Every active PID has a directory (e.g., /proc/1234/) exposing its command line arguments (cmdline), memory maps (maps), open file descriptors (fd/), and environment variables (environ).

• /sys (Sysfs Virtual Filesystem): Provides a structured, hierarchical model of the kernel device drivers, hardware buses, and system parameters, allowing engineers to query and tune hardware settings directly (e.g., adjusting network interface queues or CPU governor profiles).

Question 25: How do you write a complete, production-ready system monitoring script that alerts when disk usage exceeds 85%?

• Explanation: Here is an interview-ready implementation demonstrating clean syntax, parameter expansion, and error safety:

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

THRESHOLD=85
ALERT_EMAIL='noc-alerts@beetalogic.com'
HOSTNAME=(hostname -f)

df -PTh | awk 'NR>1 &&
2 !~ /tmpfs|squashfs|overlay/ { print 6 " " 7 }' | while read -r usage mountpoint; do
percent="{usage%%%}"
if (( percent >= THRESHOLD )); then
echo "WARNING: Partition
mountpoint on HOSTNAME is at {percent}% usage!" | \
mail -s "Disk Space Alert: HOSTNAME (mountpoint)" "ALERT_EMAIL"
fi
done
`
• Key Highlights:
-P guarantees standard POSIX single-line formatting preventing long mount point wrapping;
{usage%%%} utilizes parameter expansion to strip the trailing %` sign for clean integer comparison.

  • Audit listening ports using modern ss -tulpn rather than legacy deprecated netstat.
  • Deploy modern Ed25519 SSH keys and enforce strict permissions (700 for .ssh, 600 for authorized_keys).
  • Understand that /proc and /sys are in-memory virtual filesystems exposing kernel data structures.
  • Write robust monitoring scripts that strip unwanted filesystems and parse clean POSIX columns.

Mastering the Linux & Cloud Infrastructure Path at Beetalogic

Cracking technical interviews at Tier-1 tech giants and high-scale product startups requires far more than passive memorization. Interviewers want to see candidates who have lived in the terminal, diagnosed real memory exhaustion crises, hardened enterprise Linux environments, and automated multi-tier cloud pipelines.

At Beetalogic Software Solutions, located in Coimbatore and Chennai, our Linux Systems Engineering, Shell Automation & Cloud Administration Programs are engineered to transform students and freshers into battle-tested infrastructure specialists. You will work on real live bare-metal and cloud Linux servers, master kernel tuning, deploy automated CI/CD Bash toolchains, and train with veteran DevOps architects to ensure you clear your technical interviews with total authority.

Whether you are targeting roles as a Linux System Administrator, Cloud Engineer, DevOps Specialist, or Site Reliability Engineer, mastering the terminal is your definitive competitive advantage.

  • Hands-on terminal-first pedagogy on live production Linux cloud instances.
  • Comprehensive coverage of RHCSA/LFCS competencies and advanced Bash shell engineering.
  • Direct mentorship from senior DevOps and Cloud Infrastructure architects.
  • 100% placement support with direct interview pipelines into leading IT companies and GCCs.
B

Beetalogic DevOps & Cloud Engineering Team

Our dedicated team of tech educators at Beetalogic share insights, trends, and actionable strategies for students and professionals in Coimbatore to accelerate their careers.