LearnThatStack Ace your next interview
DevOps · Free

Shell Scripting for System Administration -.
Interview cheat sheet.

Quick reference for Shell Scripting for System Administration - - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

DevOps 15-section reference ~12 min read

Summary

Shell scripting is the cornerstone of Linux/Unix system administration, enabling automation of repetitive tasks and complex workflows. This cheatsheet covers essential Bash scripting concepts, patterns, and best practices critical for system administration interviews. Master variables, control structures, text processing, error handling, and production-ready scripting techniques that demonstrate your ability to automate infrastructure management and solve real-world operational challenges.

Shell Basics

Shebang

#!/bin/bash          # Bash shell
#!/bin/sh            # POSIX shell
#!/usr/bin/env bash  # Portable shebang

Script Execution

chmod +x script.sh   # Make executable
./script.sh          # Run script
bash script.sh       # Run with bash
source script.sh     # Run in current shell
. script.sh          # Same as source

Comments

# Single line comment
: '
Multi-line
comment
'

Variables

Variable Assignment

NAME="John"          # No spaces around =
readonly CONST=100   # Constant variable
local var="local"    # Local to function
export PATH=$PATH:/new/path  # Export to environment

Variable Types

# String
NAME="Alice"
# Integer
declare -i NUM=42
# Array
declare -a ARR=(1 2 3)
# Associative array (bash 4+)
declare -A DICT=([key1]=val1 [key2]=val2)

Variable Expansion

${VAR}               # Value of VAR
${VAR:-default}      # Use default if VAR unset/null
${VAR:=default}      # Set VAR to default if unset/null
${VAR:?error_msg}    # Exit with error if VAR unset/null
${VAR:+alt_value}    # Use alt_value if VAR is set
${#VAR}              # Length of VAR
${VAR:offset:length} # Substring
${VAR#pattern}       # Remove shortest match from start
${VAR##pattern}      # Remove longest match from start
${VAR%pattern}       # Remove shortest match from end
${VAR%%pattern}      # Remove longest match from end
${VAR/old/new}       # Replace first occurrence
${VAR//old/new}      # Replace all occurrences

Special Variables

$0    # Script name
$1-$9 # Positional parameters
${10} # 10th parameter (need braces)
$#    # Number of arguments
$@    # All arguments (array-like)
$*    # All arguments (single string)
$$    # Current process ID
$!    # Last background process ID
$?    # Exit status of last command
$-    # Current shell options

Operators

Arithmetic Operators

# Using $(( ))
result=$((5 + 3))
result=$((10 - 2))
result=$((4 * 3))
result=$((10 / 2))
result=$((10 % 3))
result=$((2 ** 3))   # Power

# Using let
let "result = 5 + 3"

# Using expr (older)
result=$(expr 5 + 3)

Comparison Operators

Numeric Comparison

-eq    # Equal
-ne    # Not equal
-gt    # Greater than
-ge    # Greater than or equal
-lt    # Less than
-le    # Less than or equal

# Example
if [ $a -gt $b ]; then
    echo "$a is greater"
fi

String Comparison

=      # Equal (POSIX)
==     # Equal (bash)
!=     # Not equal
<      # Less than (lexicographic)
>      # Greater than (lexicographic)
-z     # String is empty
-n     # String is not empty

# Example
if [ "$str1" = "$str2" ]; then
    echo "Strings are equal"
fi

File Test Operators

-e FILE    # Exists
-f FILE    # Regular file
-d FILE    # Directory
-s FILE    # File size > 0
-r FILE    # Readable
-w FILE    # Writable
-x FILE    # Executable
-L FILE    # Symbolic link
-p FILE    # Named pipe
-S FILE    # Socket
FILE1 -nt FILE2  # FILE1 newer than FILE2
FILE1 -ot FILE2  # FILE1 older than FILE2

Logical Operators

&&     # AND
||     # OR
!      # NOT

# In test expressions
[ $a -gt 0 ] && [ $b -gt 0 ]    # Both conditions
[ $a -gt 0 ] || [ $b -gt 0 ]    # Either condition
[ ! -f file.txt ]                # NOT condition

Control Structures

If-Else

if [ condition ]; then
    commands
elif [ condition ]; then
    commands
else
    commands
fi

# One-liner
[ -f file.txt ] && echo "File exists" || echo "File not found"

Case Statement

case $VAR in
    pattern1)
        commands ;;
    pattern2|pattern3)
        commands ;;
    *)
        default_commands ;;
esac

For Loop

# C-style
for ((i=0; i<10; i++)); do
    echo $i
done

# For-in loop
for item in list1 list2 list3; do
    echo $item
done

# Array iteration
for element in "${array[@]}"; do
    echo $element
done

# File iteration
for file in *.txt; do
    echo "Processing $file"
done

While Loop

while [ condition ]; do
    commands
done

# Read file line by line
while IFS= read -r line; do
    echo "$line"
done < file.txt

Until Loop

until [ condition ]; do
    commands
done

Select Menu

select option in "Option1" "Option2" "Quit"; do
    case $option in
        "Option1") echo "You chose 1" ;;
        "Option2") echo "You chose 2" ;;
        "Quit") break ;;
    esac
done

Functions

Function Definition

# Method 1
function_name() {
    commands
    return 0  # Optional return value (0-255)
}

# Method 2
function function_name {
    commands
}

Function Parameters

greet() {
    echo "Hello, $1!"  # $1 is first parameter
    echo "Args: $@"    # All parameters
    echo "Count: $#"   # Parameter count
}

greet "Alice" "Bob"

Return Values

# Return exit status (0-255)
is_even() {
    [ $(($1 % 2)) -eq 0 ]
}

# Return value via echo
get_sum() {
    echo $(($1 + $2))
}

# Usage
if is_even 4; then
    echo "Even"
fi

result=$(get_sum 5 3)

Input/Output

Read Input

read var                 # Read into variable
read -p "Enter name: " name  # With prompt
read -s password        # Silent (for passwords)
read -t 5 var          # Timeout after 5 seconds
read -n 1 char         # Read single character
read -a array          # Read into array

Output Redirection

command > file          # Redirect stdout to file
command >> file         # Append stdout to file
command 2> file         # Redirect stderr to file
command 2>&1            # Redirect stderr to stdout
command &> file         # Redirect both to file
command < file          # Redirect stdin from file
command << EOF          # Here document
text
EOF
command <<< "string"    # Here string

File Descriptors

exec 3< input.txt       # Open file for reading on FD 3
exec 4> output.txt      # Open file for writing on FD 4
read -u 3 line          # Read from FD 3
echo "text" >&4         # Write to FD 4
exec 3<&-               # Close FD 3

File Operations

Basic File Commands

touch file.txt          # Create empty file
mkdir -p dir/subdir     # Create directory tree
cp -r source dest       # Copy recursively
mv old new              # Move/rename
rm -rf dir              # Remove recursively
chmod 755 file          # Change permissions
chown user:group file   # Change ownership

File Manipulation

# Check if file exists
[ -f file.txt ] && echo "File exists"

# Create temp file
tempfile=$(mktemp)
trap "rm -f $tempfile" EXIT

# Find files
find /path -name "*.txt" -type f -mtime -7

# Archive
tar -czf archive.tar.gz directory/
tar -xzf archive.tar.gz

Process Management

Process Control

command &               # Run in background
jobs                    # List background jobs
fg %1                   # Bring job 1 to foreground
bg %1                   # Resume job 1 in background
kill PID                # Kill process
kill -9 PID             # Force kill
killall process_name    # Kill by name

Process Information

ps aux                  # List all processes
ps -ef                  # Full format listing
pgrep process_name      # Get PID by name
pidof process_name      # Get PID by exact name

Signals and Traps

# Trap signals
trap 'echo "Interrupted"' INT
trap 'cleanup' EXIT
trap '' TERM            # Ignore SIGTERM

# Common signals
# INT (2) - Interrupt (Ctrl+C)
# TERM (15) - Terminate
# KILL (9) - Force kill
# HUP (1) - Hangup

Text Processing

grep - Search Text

grep pattern file              # Search pattern in file
grep -i pattern file           # Case insensitive
grep -r pattern dir/           # Recursive search
grep -v pattern file           # Invert match
grep -n pattern file           # Show line numbers
grep -E 'regex' file           # Extended regex

sed - Stream Editor

sed 's/old/new/' file          # Replace first occurrence
sed 's/old/new/g' file         # Replace all occurrences
sed -i 's/old/new/g' file      # In-place edit
sed -n '5p' file               # Print line 5
sed '1,5d' file                # Delete lines 1-5
sed '/pattern/d' file          # Delete matching lines

awk - Text Processing

awk '{print $1}' file          # Print first column
awk -F: '{print $1}' /etc/passwd  # Custom delimiter
awk 'NR==5' file               # Print line 5
awk '$3 > 100' file            # Conditional print
awk '{sum+=$1} END {print sum}' file  # Sum column

cut - Extract Columns

cut -d: -f1 /etc/passwd        # Cut by delimiter
cut -c1-10 file                # Cut characters 1-10
cut -f2,4 file                 # Cut fields 2 and 4

sort and uniq

sort file                      # Sort alphabetically
sort -n file                   # Sort numerically
sort -r file                   # Reverse sort
sort -k2 file                  # Sort by column 2
uniq file                      # Remove duplicates
uniq -c file                   # Count occurrences
sort file | uniq               # Sort then deduplicate

System Administration

User Management

# Check current user
whoami
id

# Switch user
su - username
sudo command

# User info
getent passwd username
groups username

System Information

uname -a                       # System info
hostname                       # Hostname
uptime                         # System uptime
df -h                          # Disk usage
du -sh directory/              # Directory size
free -h                        # Memory usage
top                            # Process monitor
lscpu                          # CPU info

Network Commands

ifconfig                       # Network interfaces (old)
ip addr show                   # Network interfaces (new)
netstat -tuln                  # Network connections
ss -tuln                       # Socket statistics
ping -c 4 google.com          # Test connectivity
curl -I https://example.com    # HTTP headers
wget https://example.com/file  # Download file

Service Management

# SystemD (modern)
systemctl start service
systemctl stop service
systemctl restart service
systemctl status service
systemctl enable service       # Start at boot

# SysV (older)
service name start
/etc/init.d/service start

Log Management

tail -f /var/log/syslog        # Follow log
journalctl -u service          # SystemD logs
grep ERROR /var/log/app.log    # Search logs
logrotate -f /etc/logrotate.conf  # Force log rotation

Advanced Topics

Command Substitution

# Modern syntax
result=$(command)
result=$(command1 | command2)

# Old syntax (avoid)
result=`command`

Process Substitution

diff <(ls dir1) <(ls dir2)    # Compare outputs
while read line; do
    echo "$line"
done < <(command)              # Read from command output

Arrays

# Indexed arrays
arr=(a b c)
arr[3]=d
echo ${arr[0]}                 # First element
echo ${arr[@]}                 # All elements
echo ${#arr[@]}                # Array length

# Associative arrays
declare -A dict
dict[key1]=value1
dict[key2]=value2
echo ${dict[key1]}
echo ${!dict[@]}               # All keys

Regular Expressions

# Basic regex matching
[[ "string" =~ regex ]]

# Example
if [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
    echo "Valid email"
fi

# Capture groups
if [[ "user123" =~ ([a-z]+)([0-9]+) ]]; then
    echo "User: ${BASH_REMATCH[1]}"
    echo "Number: ${BASH_REMATCH[2]}"
fi

Debugging

set -x          # Print commands before execution
set -e          # Exit on error
set -u          # Exit on undefined variable
set -o pipefail # Exit on pipe failure
set -euo pipefail  # Combine all

# Debug specific section
set -x
commands
set +x

Performance Tips

# Use built-in commands when possible
# Bad: cat file | grep pattern
# Good: grep pattern file

# Avoid useless use of cat
# Bad: cat file | command
# Good: command < file

# Use parameter expansion instead of external commands
# Bad: echo $string | cut -c1-5
# Good: echo ${string:0:5}

Best Practices

Error Handling

#!/bin/bash
set -euo pipefail

error_exit() {
    echo "Error: $1" >&2
    exit 1
}

# Check command existence
command -v git >/dev/null 2>&1 || error_exit "git not found"

# Check file existence
[ -f "config.txt" ] || error_exit "Config file not found"

Script Template

#!/bin/bash
#
# Script: script_name.sh
# Description: Brief description
# Author: Your Name
# Date: $(date +%Y-%m-%d)
#

set -euo pipefail
IFS=$'\n\t'

# Constants
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "$0")"

# Functions
usage() {
    cat << EOF
Usage: $SCRIPT_NAME [OPTIONS]
Options:
    -h, --help     Show this help message
    -v, --verbose  Enable verbose mode
EOF
}

# Main
main() {
    # Parse arguments
    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help) usage; exit 0 ;;
            -v|--verbose) VERBOSE=1 ;;
            *) echo "Unknown option: $1"; usage; exit 1 ;;
        esac
        shift
    done
    
    # Main logic here
}

# Run main function
main "$@"

Security Best Practices

# Quote variables
rm "$file"  # Not rm $file

# Use -- to separate options from arguments
grep -- "$pattern" file

# Validate input
if [[ ! "$input" =~ ^[a-zA-Z0-9_-]+$ ]]; then
    error_exit "Invalid input"
fi

# Use mktemp for temporary files
tempfile=$(mktemp)
trap 'rm -f "$tempfile"' EXIT

# Avoid eval
# Bad: eval "command $user_input"
# Good: Use arrays or proper quoting

Common Interview Scenarios

1. Monitor Disk Usage

#!/bin/bash
# Alert if disk usage exceeds threshold
THRESHOLD=80
df -h | awk 'NR>1 {gsub(/%/,"",$5); if($5 > '"$THRESHOLD"') print "Alert: "$1" is "$5"% full"}'

2. Log Rotation Script

#!/bin/bash
# Rotate logs when size exceeds limit
MAX_SIZE=1048576  # 1MB
LOG_FILE="/var/log/app.log"

if [ -f "$LOG_FILE" ] && [ $(stat -f%z "$LOG_FILE" 2>/dev/null || stat -c%s "$LOG_FILE") -gt $MAX_SIZE ]; then
    mv "$LOG_FILE" "$LOG_FILE.$(date +%Y%m%d_%H%M%S)"
    touch "$LOG_FILE"
fi

3. Backup Script

#!/bin/bash
# Daily backup with retention
BACKUP_DIR="/backup"
SOURCE_DIR="/data"
RETENTION_DAYS=7

# Create backup
tar -czf "$BACKUP_DIR/backup_$(date +%Y%m%d).tar.gz" "$SOURCE_DIR"

# Remove old backups
find "$BACKUP_DIR" -name "backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete

4. Process Monitor

#!/bin/bash
# Restart service if not running
SERVICE="nginx"

if ! pgrep -x "$SERVICE" > /dev/null; then
    echo "Starting $SERVICE..."
    systemctl start "$SERVICE"
fi

5. User Creation Script

#!/bin/bash
# Bulk user creation from file
while IFS=: read -r username password; do
    if ! id "$username" &>/dev/null; then
        useradd -m "$username"
        echo "$username:$password" | chpasswd
        echo "Created user: $username"
    fi
done < users.txt

6. System Health Check

#!/bin/bash
# Basic system health report
echo "=== System Health Report ==="
echo "Hostname: $(hostname)"
echo "Uptime: $(uptime -p)"
echo "Load Average: $(uptime | awk -F'load average:' '{print $2}')"
echo "Memory Usage: $(free -h | awk '/^Mem:/ {print $3"/"$2}')"
echo "Disk Usage:"
df -h | grep -E '^/dev/' | awk '{print $1": "$3"/"$2" ("$5")"}'

7. Find and Replace in Multiple Files

#!/bin/bash
# Replace text in all files recursively
find . -type f -name "*.txt" -exec sed -i 's/oldtext/newtext/g' {} +

8. Parse CSV File

#!/bin/bash
# Process CSV file
while IFS=, read -r col1 col2 col3; do
    echo "Processing: $col1, $col2, $col3"
done < file.csv

9. Check Service Status Across Multiple Servers

#!/bin/bash
# Check nginx status on multiple servers
SERVERS=("server1" "server2" "server3")
SERVICE="nginx"

for server in "${SERVERS[@]}"; do
    echo -n "$server: "
    ssh "$server" "systemctl is-active $SERVICE" 2>/dev/null || echo "Failed"
done

10. Archive Old Files

#!/bin/bash
# Archive files older than 30 days
find /logs -name "*.log" -mtime +30 -exec tar -rf archive.tar {} \; -exec rm {} \;
gzip archive.tar

Quick Reference Card

Essential One-Liners

# Count lines in file
wc -l file.txt

# Find largest files
find . -type f -exec du -h {} + | sort -rh | head -10

# Monitor log in real-time
tail -f /var/log/syslog | grep ERROR

# Kill process by port
lsof -ti:8080 | xargs kill -9

# Check listening ports
netstat -tuln | grep LISTEN

# Find files modified in last 24h
find . -mtime -1 -type f

# Replace string in multiple files
find . -name "*.conf" -exec sed -i 's/old/new/g' {} +

# Check SSL certificate expiry
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

# Generate random password
openssl rand -base64 32

# Quick backup with timestamp
tar -czf "backup_$(date +%Y%m%d_%H%M%S).tar.gz" /important/data

Common Pitfalls to Avoid

  1. Unquoted variables: Always quote "$var"
  2. Using backticks: Use $(command) instead of `command`
  3. Not checking exit codes: Use set -e or check $?
  4. Parsing ls output: Use glob patterns or find instead
  5. Not handling spaces in filenames: Use proper quoting and IFS
  6. Using cat unnecessarily: Many commands can read files directly
  7. Not validating user input: Always sanitize external input
  8. Forgetting to make scripts executable: Use chmod +x

Interview Tips

  • Know the difference between [ and [[
  • Understand when to use source vs executing a script
  • Be familiar with exit codes and their meanings
  • Know how to handle signals and write trap handlers
  • Understand the difference between $@ and $*
  • Be able to explain shell expansion order
  • Know common performance optimizations
  • Be prepared to debug scripts using set -x

Remember: The best shell script is readable, maintainable, and handles errors gracefully. Always test your scripts thoroughly before using them in production.

Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime