Shell scripting originated in the 1970s with the Bourne Shell (sh), developed by Stephen Bourne at Bell Labs for Unix.
Over time, modern shells emerged to add interactive features and programming enhancements. The most prominent is the Bourne-Again Shell (bash), written by Brian Fox in 1989 as a free software replacement for sh under the GNU project.
Today, POSIX standard shell scripting (sh) provides baseline compatibility across Unix-like systems, while bash remains the default shell script environment for most Linux distributions and developers.
Who:
Stephen Bourne (Bourne Shell), Brian Fox (Bash), and the open-source GNU community.
Why:
Developed to automate system administration tasks, coordinate execution of separate compiler/system utilities, and provide an expressive command execution language.
Introduction
Advantages
High System Integration — Direct access to filesystem utilities, command-line arguments, system environments, and other compiled executables.
Fast Automation — Perfect for quick scripting tasks, file manipulation, build automation, and server deployments.
Interactive Portability — POSIX compliant scripts run on virtually any Unix-like OS (Linux, macOS, BSD) without needing runtime engine compilation.
Flexible Piping — Effortlessly redirects stream inputs/outputs between utilities using pipe operations.
Disadvantages
Performance Overhead — High overhead as shell processes spawn external subprocess commands for simple operations (e.g. executing grep or sed).
Syntax Quirks — Extreme sensitivity to whitespace, confusing syntax rules (such as brackets vs double brackets), and tricky quote escaping rules.
Weak Data Structuring — Poor support for complex data types. Missing objects, structs, or nested arrays (hashes/arrays are flat).
Fragile Error Handling — Scripts continue executing after commands fail by default, requiring explicit options (set -e) to prevent disastrous cascade failures.
Quote Your Variables — Always use double quotes around variables (e.g., "$var") to prevent word splitting and glob expansions.
Check Exit Codes — Every command returns 0 for success and 1-255 for errors/failures.
Basics
Hello World & Entry Point
#!/bin/bash# This is a commentprint_message="Hello, World!"echo "$print_message"
The first line #!/bin/bash is the Shebang, indicating the path of the interpreter to run this file. Use #!/bin/sh for POSIX-only compatibility.
Execution permissions must be set using command line: chmod +x script.sh. Run the script with ./script.sh.
Variables and Scopes
# 1. Global Variables (Default)global_var="I am global"# 2. Local Variables (Restricted to function body)my_function() { local local_var="I am local" echo "$local_var"}# 3. Environment Variables (Exported to child processes)export API_KEY="secure_token_123"# 4. Read-Only Constantsreadonly PI=3.14159# PI=3.14 // Fails with error: PI: readonly variable
Quoting Rules
name="VR"# Double Quotes (Weak Quoting) - Evaluates variables and escape charactersecho "Hello $name\n" # Output: Hello VR (followed by newline)# Single Quotes (Strong Quoting) - Prints literal string contents without evaluationecho 'Hello $name\n' # Output: Hello $name\n
Operation Numeric Operator String Operator
Equality -eq == or =
Inequality -ne !=
Greater Than -gt \>
Less Than -lt \<
Greater or Equal -ge -z (if empty)
Less or Equal -le -n (if not empty)
# 1. Standard For Loop (with range expansion)for i in {1..5}; do echo "Count: $i"done# 2. C-Style For Loopfor ((i=0; i<3; i++)); do echo "Index: $i"done# 3. While Loopcount=0while [[ $count -lt 3 ]]; do echo "While count: $count" ((count++))done# 4. Loop Control (break & continue)for n in {1..10}; do if [[ $n -eq 3 ]]; then continue # Skip 3 fi if [[ $n -eq 7 ]]; then break # Stop at 7 fi echo "$n"done
Statement Modifiers / Boolean Shortcuts
# && runs second command only if first succeeds (exit code 0)# || runs second command only if first fails (exit code non-zero)[[ -f "config.txt" ]] && echo "Config file exists"[[ -d "logs" ]] || mkdir "logs"
Functions
Declaration & Arguments
# Functions read parameters from index variables ($1, $2, etc.)calculate_sum() { local num1=$1 local num2=$2 local sum=$((num1 + num2)) echo "$sum" # Return value by printing to stdout}# Invoke function (do not use parentheses when calling)result=$(calculate_sum 5 10)echo "Result: $result" # 15
Exit Codes & Returns
# The 'return' keyword sets the exit status (0-255), not returning valuescheck_file() { if [[ -f "$1" ]]; then return 0 # Success else return 1 # Error fi}check_file "data.txt"if [[ $? -eq 0 ]]; then echo "File found"fi
Special Variables
Command Line Arguments
Variable Description
$0 Name of the script being executed
$1, $2, ... First, second, etc. command line arguments
$# Number of arguments passed to script
$@ Array representation of all arguments (safe for spacing with "$@")
$* Single string representation of all arguments
$? Exit status of the last executed command (0 = success)
$$ Process ID (PID) of the current shell running script
$! Process ID (PID) of the last background command run
Arrays (Bash 4+)
Indexed Arrays
# Declare arraymy_array=("apple" "banana" "cherry")# Add elementsmy_array+=("date")# Access elements (Requires curly brackets)echo "${my_array[0]}" # apple# Size of arrayecho "${#my_array[@]}" # 4# List all indicesecho "${!my_array[@]}" # 0 1 2 3# Loop through array elementsfor item in "${my_array[@]}"; do echo "Fruit: $item"done
Associative Arrays (Key-Value)
# Declare associative array explicitlydeclare -A user_agesuser_ages["Alice"]=28user_ages["Bob"]=34echo "${user_ages["Alice"]}" # 28
Placing these options at the top of scripts improves crash resiliency and debugging:
set -e # Exit script immediately if any command fails (non-zero status)set -u # Exit script immediately if an undeclared variable is accessedset -o pipefail # Prevents errors in pipelines from being masked (returns status of last failing step)set -x # Print commands before execution (tracing execution flow in terminal)# Shorthand for robust scripting:# set -euo pipefail
Useful Command Line Utilities
awk - Pattern scanning and processing language for structured data fields.
sed - Stream editor for filtering and transforming text stream.
grep - Matches input strings against regular expression patterns.
xargs - Build and execute command lines from standard input.