Bash Scripting
Cheatsheet
A practical reference for Bash shell scripting — covering variables, loops, conditionals, functions, arrays, string operations, and real-world script patterns.
What is Bash?
Bash (Bourne Again SHell) is the default command-line interpreter on most Linux distributions and macOS. It is both an interactive shell (for running commands) and a scripting language (for writing automation scripts saved in .sh files).
Why use it? Bash scripts automate repetitive tasks, system administration, deployments, log parsing, backups, and CI/CD pipelines. A single Bash script can replace hours of manual work.
Real-world use: DevOps engineers, sysadmins, security analysts, and developers use Bash daily. It is core to Linux system administration, Ansible playbooks, Docker entrypoints, and GitHub Actions workflows.
#!/bin/bash
This tells the OS to use /bin/bash to interpret the script. Save with .sh extension and make executable: chmod +x script.sh
1. Getting Started
#!/bin/bash # This is a comment # Print output echo "Hello, World!" echo "Today: $(date)" # command substitution # Exit codes exit 0 # 0 = success exit 1 # non-zero = error echo $? # print last exit code # Make script executable and run # chmod +x script.sh && ./script.sh
2. Variables
# Assign (no spaces around =) NAME="Kenneth" AGE=25 DIR="/var/www" # Use variable echo "Hello, $NAME" echo "Age: ${AGE}" # braces for clarity # Command substitution HOSTNAME=$(hostname) FILES=$(ls /etc | wc -l) # Read-only variable readonly PI=3.14159 # Unset variable unset NAME # Special variables echo $0 # script name echo $1 # first argument echo $# # number of arguments echo $@ # all arguments echo $$ # current PID echo $? # last exit code
3. User Input
# Read from user read -p "Enter your name: " NAME echo "Hello, $NAME!" # Silent input (for passwords) read -sp "Password: " PASS echo # newline after hidden input # Read with timeout read -t 10 -p "Input (10s): " INPUT # Command-line arguments #!/bin/bash echo "Script: $0" echo "Arg 1: $1" echo "Arg 2: $2" echo "All args: $@" # Run: ./script.sh hello world
4. Conditionals
if / elif / else
if [ $AGE -ge 18 ]; then echo "Adult" elif [ $AGE -ge 13 ]; then echo "Teen" else echo "Child" fi # String comparison if [ "$NAME" == "root" ]; then echo "Root user" fi
Test operators
# Numeric -eq equal to -ne not equal -lt less than -le less or equal -gt greater than -ge greater or equal # String == equal != not equal -z empty string -n not empty # File tests -f is a file -d is a directory -e exists -r readable -x executable
# File tests in practice if [ -f "/etc/passwd" ]; then echo "File exists" fi if [ ! -d "/tmp/mydir" ]; then mkdir -p /tmp/mydir fi # Compound conditions if [[ $AGE -gt 18 && "$NAME" != "" ]]; then echo "Valid adult" fi # case statement case $OS in Ubuntu) echo "Debian-based" ;; CentOS) echo "RPM-based" ;; *) echo "Unknown" ;; esac
5. Loops
# for loop — iterate list for i in 1 2 3 4 5; do echo "Number: $i" done # for loop — range for i in {1..10}; do echo $i done # for loop — C-style for (( i=0; i<5; i++ )); do echo "i=$i" done # for loop — iterate files for file in /var/log/*.log; do echo "Processing: $file" done # while loop COUNT=0 while [ $COUNT -lt 5 ]; do echo "Count: $COUNT" COUNT=$((COUNT + 1)) done # Read file line by line while IFS= read -r line; do echo "$line" done < /etc/hosts # until loop until [ $COUNT -ge 10 ]; do COUNT=$((COUNT + 1)) done # Loop control break # exit loop continue # skip to next iteration
6. Functions
# Define a function greet() { local NAME=$1 # local variable (scoped) echo "Hello, $NAME!" } # Call the function greet "Kenneth" # Function with return value add() { local RESULT=$(( $1 + $2 )) echo $RESULT # return via stdout } SUM=$(add 5 3) echo "Sum: $SUM" # Function with exit code check_root() { if [ $EUID -ne 0 ]; then echo "Must be root" >&2 return 1 fi } check_root || exit 1 # exit if not root
7. Arrays
# Declare array FRUITS=("apple" "banana" "cherry") NUMBERS=(1 2 3 4 5) # Access elements echo ${FRUITS[0]} # apple echo ${FRUITS[1]} # banana echo ${FRUITS[-1]} # last element (cherry) # All elements echo ${FRUITS[@]} # all elements echo ${#FRUITS[@]} # array length # Loop over array for fruit in ${FRUITS[@]}; do echo $fruit done # Add / remove elements FRUITS+=("date") # append unset FRUITS[0] # remove index 0 # Associative arrays (dictionaries) declare -A PORTS PORTS["HTTP"]=80 PORTS["HTTPS"]=443 PORTS["SSH"]=22 echo ${PORTS["HTTPS"]} # 443
8. String Operations
STR="Hello World" # Length echo ${#STR} # 11 # Uppercase / lowercase echo ${STR^^} # HELLO WORLD echo ${STR,,} # hello world # Substring echo ${STR:0:5} # Hello (pos 0, length 5) echo ${STR:6} # World (from pos 6) # Replace echo ${STR/World/Bash} # Hello Bash (first) echo ${STR//l/L} # HeLLo WorLd (all) # Strip prefix / suffix FILE="report.txt" echo ${FILE%.txt} # report (strip suffix) echo ${FILE#report} # .txt (strip prefix) # Default values echo ${VAR:-"default"} # use default if VAR unset echo ${VAR:="default"} # set and use default if unset
9. Arithmetic
# Arithmetic expansion RESULT=$(( 5 + 3 )) # 8 RESULT=$(( 10 / 2 )) # 5 RESULT=$(( 7 % 3 )) # 1 (modulus) RESULT=$(( 2 ** 8 )) # 256 (power) # Increment / decrement COUNT=0 (( COUNT++ )) # post-increment (( COUNT += 5 )) # add 5 COUNT=$(( COUNT - 1 )) # subtract 1 # Float arithmetic (use bc) echo "scale=2; 10/3" | bc # 3.33 AREA=$(echo "scale=2; 3.14 * 5 * 5" | bc)
10. Real-World Script Patterns
#!/bin/bash # Robust script template set -euo pipefail # exit on error, unset var, pipe fail IFS=$'\n\t' # safer word splitting # Log function log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" ; } # Error handler die() { echo "ERROR: $*" >&2; exit 1; } # Check dependency require() { command -v "$1" >/dev/null || die "$1 not found" } require curl require jq # Trap cleanup on exit cleanup() { log "Cleaning up..." rm -f /tmp/tmpfile.$$ } trap cleanup EXIT log "Starting script..."