Shell Scripting Basics: Variables, User Input, and Loops
Shell scripting is the cornerstone of automation in DevOps and system administration. It allows engineers to chain terminal commands, process system outputs, manage server state, and eliminate repetitive manual workflows through programmatic execution.
1. Why Do We Need Shell Scripting?
When managing Linux servers, performing tasks interactively by typing individual commands into a shell prompt is slow, error-prone, and non-reproducible. Shell scripting packages these commands into executable files that run sequentially, conditionally, or repeatedly.
Real-Life Analogy
Think of interactive terminal commands as ordering food item-by-item from a waiter. You ask for water, wait, ask for the menu, wait, and order your main course. A shell script is like placing a pre-written catering sheet with explicit instructions: if the dish is unavailable, substitute it; once complete, bring the check.
2. Anatomy of a Shell Script & The Shebang
Every bash script begins with a specialized line known as the Shebang (#!/bin/bash).
#!/bin/bash
# Description: Basic system information printer
echo "Starting System Audit..."
Key Components
- Shebang (
#!/bin/bash): Instructs the operating system's kernel to execute the rest of the script using the Bash shell interpreter located at/bin/bash. - Comments (
#): Lines beginning with#(except the shebang) are ignored by the shell and serve as documentation. - Execution Permissions: By default, newly created text files do not have execution privileges. You must assign permission using
chmod:
chmod +x script.sh
./script.sh
3. Working with Variables
Variables store data (such as hostnames, user input, dynamic process IDs, or configuration paths) for reuse throughout a script.
Syntax Rules
- No Spaces Around Assignment:
KEY=VALUE(WritingKEY = VALUEcauses a syntax error because Bash attempts to runKEYas a command). - Case Sensitivity: By convention, user-defined variables are written in lowercase or snake_case (
user_name), while environment and system variables are uppercase (PATH,USER,HOME).
#!/bin/bash
# Variable Declaration
SERVER_NAME="prod-api-01"
PORT=8080
# Accessing Variables using $ or ${}
echo "Connecting to $SERVER_NAME on port ${PORT}..."
Variable Substitution Comparison
4. Capturing User Input (read)
To create dynamic scripts, you can accept interactive user input from standard input (stdin) using the read command.
Common read Patterns
#!/bin/bash
# 1. Standard Prompt
echo "Enter target environment (dev/
stage/prod):"
read ENVIRONMENT
# 2. Combined Prompt Flag (-p)
read -p "Enter your deployment username: " USERNAME
# 3. Silent Input for Passwords/Secrets (-s)
read -sp "Enter API Secret Token: " API_TOKEN
echo "" # Line break after hidden input
echo "Deploying as $USERNAME to $ENVIRONMENT..."
5. Decision Making: Conditional Logic (if/else)
Conditionals allow scripts to make decisions based on string values, numerical evaluations, or file checks.
Numerical and String Comparison Operators
Conditional Structure Syntax
#!/bin/bash
read -p "Enter disk usage percentage: " DISK_USAGE
if [ "$DISK_USAGE" -ge 90 ]; then
echo "CRITICAL: Disk space nearly full!"
elif [ "$DISK_USAGE" -ge 75 ]; then
echo "WARNING: Disk space usage elevated."
else
echo "INFO: Disk space operating within normal parameters."
fi
Note: Always leave spaces inside the single square brackets
[ ... ].[ "$VAR" == "test" ]is valid, whereas["$VAR"=="test"]will fail because[is actually a command alias fortest.
6. Loop Constructs (for and while)
Loops allow you to iterate over lists of items, sequence numbers, or run tasks continuously until a specific condition is met.
1. for Loops
Used when the number of iterations or the item list is known in advance.
#!/bin/bash
# Iterating over a list of items
for SERVICE in nginx mysql redis; do
echo "Checking status of service: $SERVICE"
done
# Iterating over a numeric range
for i in {1..5}; do
echo "Attempt $i of 5"
done
2. while Loops
Used when execution should continue as long as a condition evaluates to true.
#!/bin/bash
COUNTER=1
while [ $COUNTER -le 3 ]; do
echo "Processing batch $COUNTER..."
COUNTER=$((COUNTER + 1)) # Arithmetic expansion
done
Loop Type Summary
7. Complete Walkthrough: Automated User Provisioning Script
The following script combines variables, user input, conditionals, and loops to parse a list of requested users, validate administrative privileges, and set up system access.
#!/bin/bash
# ------------------------------------------------------------------
# Script Name: system_provisioner.sh
# Purpose: Automate user creation and directory setup
# ------------------------------------------------------------------
# 1. Enforce Execution as Root
if [ "$EUID" -ne 0 ]; then
echo "ERROR: This script must be run as root (or via sudo)."
exit 1
fi
# 2. Capture System Environment via User Input
read -p "Enter Target Department [dev/ops/qa]: " DEPT
# Validate Department Input
if [ -z "$DEPT" ]; then
echo "Department cannot be empty. Exiting."
exit 1
fi
# 3. Define User Array
USERS="alice bob charlie"
echo "=========================================="
echo " Starting Provisioning for Dept: $DEPT"
echo "=========================================="
# 4. Process Users with Loop Logic
for USERNAME in $USERS; do
# Check if user already exists
if id "$USERNAME" &>/dev/null; then
echo "USER EXISTS: Account '$USERNAME' is already configured."
else
echo "CREATING USER: Generating account for '$USERNAME'..."
# Simulated user creation
mkdir -p "/home/departments/$DEPT/$USERNAME"
echo "SUCCESS: Created workspace directory for $USERNAME."
fi
done
echo "=========================================="
echo " Provisioning Completed Successfully."
echo "=========================================="
8. Common Pitfalls and Debugging Strategies
When developing shell scripts, small syntax oversights can cause silent failures or system errors.
Pitfalls & Best Practices
- Unquoted Variables: Unquoted variables containing spaces can break multi-word strings into separate arguments.
- Bad:
if [ $NAME == "John Doe" ] - Good:
if [ "$NAME" == "John Doe" ]
- Bad:
- Missing Spaces in Test Expressions:
- Bad:
if [$VAR -eq 5] - Good:
if [ "$VAR" -eq 5 ]
- Bad:
- Forgetting Permission Flags: Executing
./script.shwithoutchmod +xreturnsPermission denied.
Debugging Modes
Enable shell flags at the top of your script to make error tracing explicit:
#!/bin/bash
set -e # Exit immediately if any command returns a non-zero (failure) status
set -x # Print each command to stdout before executing it (Trace Mode)
Summary and Key Takeaways
- Shebang Mandate: Always start shell scripts with
#!/bin/bashto specify the execution engine. - Variable Formatting: Never insert spaces around the assignment operator
=(VAR="value"). - Quoting Rules: Use double quotes (
"...") when referencing variables containing dynamic values to preserve internal whitespace and prevent word splitting. Single quotes ('...') suppress variable expansion entirely. - User Input: Use
read -pfor standard interactive input andread -spfor sensitive entries like passwords or tokens. - Conditionals: Evaluate conditions using
if [ condition ]; then ... fi. Keep whitespace inside evaluation brackets[ ... ]. - Iteration: Use
forloops for known lists or ranges, andwhileloops for continuous conditional polling. - Script Robustness: Always incorporate validation steps (like verifying
rootprivileges via$EUID) before performing administrative actions. - Debugging: Add
set -xfor execution tracing andset -eto halt execution upon encountering unhandled command failures.