#Bash Scripting

Bash is the default shell on most Linux systems and essential for DevOps automation.

#📋 Table of Contents


#Script Basics

#Creating a Script

bash
1#!/bin/bash
2# This is a comment
3# script-name.sh - Description of script
4
5echo "Hello, DevOps!"

#Running Scripts

bash
1# Make executable
2chmod +x script.sh
3
4# Run
5./script.sh
6
7# Or with bash
8bash script.sh

#Shebang Options

bash
#!/bin/bash           # Standard bash
#!/usr/bin/env bash   # Portable (finds bash in PATH)
#!/bin/sh             # POSIX shell (more portable)

#Variables

#Basic Variables

bash
1# Assignment (no spaces around =)
2name="DevOps"
3count=42
4
5# Using variables
6echo "Hello, $name"
7echo "Count: ${count}"
8
9# Command substitution
10current_date=$(date +%Y-%m-%d)
11hostname=$(hostname)
12
13# Read-only
14readonly PI=3.14159
15
16# Arrays
17servers=("web-01" "web-02" "web-03")
18echo "First: ${servers[0]}"
19echo "All: ${servers[@]}"
20echo "Count: ${#servers[@]}"

#Special Variables

bash
1$0          # Script name
2$1, $2, $3  # Positional arguments
3$#          # Number of arguments
4$@          # All arguments as separate words
5$*          # All arguments as single string
6$?          # Exit status of last command
7$$          # Current process ID
8$!          # PID of last background process

#Environment Variables

bash
1# Export for child processes
2export MY_VAR="value"
3
4# Common variables
5echo "User: $USER"
6echo "Home: $HOME"
7echo "Path: $PATH"
8echo "Shell: $SHELL"

#Control Flow

#If Statements

bash
1# Basic if
2if [ "$name" = "DevOps" ]; then
3    echo "Match!"
4fi
5
6# If-else
7if [ -f "/etc/nginx/nginx.conf" ]; then
8    echo "Nginx is installed"
9else
10    echo "Nginx not found"
11fi
12
13# If-elif-else
14if [ "$status" = "healthy" ]; then
15    echo "All good"
16elif [ "$status" = "warning" ]; then
17    echo "Check logs"
18else
19    echo "Critical!"
20fi
21
22# Using [[ ]] for extended tests (bash-specific)
23if [[ "$name" == Dev* ]]; then
24    echo "Starts with Dev"
25fi

#Test Operators

bash
1# String comparisons
2[ "$a" = "$b" ]     # Equal
3[ "$a" != "$b" ]    # Not equal
4[ -z "$a" ]         # Zero length
5[ -n "$a" ]         # Non-zero length
6
7# Numeric comparisons
8[ "$a" -eq "$b" ]   # Equal
9[ "$a" -ne "$b" ]   # Not equal
10[ "$a" -lt "$b" ]   # Less than
11[ "$a" -gt "$b" ]   # Greater than
12[ "$a" -le "$b" ]   # Less or equal
13[ "$a" -ge "$b" ]   # Greater or equal
14
15# File tests
16[ -f "$file" ]      # Is file
17[ -d "$dir" ]       # Is directory
18[ -e "$path" ]      # Exists
19[ -r "$file" ]      # Readable
20[ -w "$file" ]      # Writable
21[ -x "$file" ]      # Executable
22[ -s "$file" ]      # Non-zero size
23
24# Logical operators
25[ cond1 ] && [ cond2 ]  # AND
26[ cond1 ] || [ cond2 ]  # OR
27[ ! cond ]              # NOT

#Loops

bash
1# For loop - list
2for server in web-01 web-02 web-03; do
3    echo "Processing $server"
4done
5
6# For loop - array
7servers=("web-01" "web-02" "web-03")
8for server in "${servers[@]}"; do
9    echo "Processing $server"
10done
11
12# For loop - range
13for i in {1..10}; do
14    echo "Number: $i"
15done
16
17# For loop - C-style
18for ((i=0; i<10; i++)); do
19    echo "Index: $i"
20done
21
22# For loop - files
23for file in /etc/*.conf; do
24    echo "Config: $file"
25done
26
27# While loop
28count=0
29while [ $count -lt 5 ]; do
30    echo "Count: $count"
31    ((count++))
32done
33
34# Read file line by line
35while IFS= read -r line; do
36    echo "Line: $line"
37done < file.txt
38
39# Infinite loop with break
40while true; do
41    if [ -f "/tmp/stop" ]; then
42        break
43    fi
44    sleep 1
45done

#Case Statement

bash
1case "$action" in
2    start)
3        echo "Starting..."
4        ;;
5    stop)
6        echo "Stopping..."
7        ;;
8    restart)
9        echo "Restarting..."
10        ;;
11    *)
12        echo "Usage: $0 {start|stop|restart}"
13        exit 1
14        ;;
15esac

#Functions

bash
1# Simple function
2greet() {
3    echo "Hello, $1!"
4}
5
6greet "DevOps"
7
8# Function with return value
9is_healthy() {
10    local host=$1
11    ping -c 1 "$host" &>/dev/null
12    return $?
13}
14
15if is_healthy "google.com"; then
16    echo "Host is reachable"
17fi
18
19# Function with output
20get_ip() {
21    hostname -I | awk '{print $1}'
22}
23
24my_ip=$(get_ip)
25echo "My IP: $my_ip"
26
27# Local variables
28calculate() {
29    local result=$(( $1 + $2 ))
30    echo $result
31}
32
33sum=$(calculate 5 3)

#Input and Output

#Reading Input

bash
1# Read from user
2read -p "Enter name: " name
3echo "Hello, $name"
4
5# Read with default
6read -p "Port [8080]: " port
7port=${port:-8080}
8
9# Read password (hidden)
10read -sp "Password: " password
11echo
12
13# Read with timeout
14read -t 5 -p "Quick! " answer

#Output Redirection

bash
1# Redirect stdout
2echo "log message" > file.txt      # Overwrite
3echo "log message" >> file.txt     # Append
4
5# Redirect stderr
6command 2> errors.txt
7
8# Redirect both
9command > output.txt 2>&1
10command &> output.txt              # Bash shorthand
11
12# Discard output
13command > /dev/null 2>&1
14
15# Pipe to another command
16cat file.txt | grep "error" | wc -l

#Here Documents

bash
1# Multi-line input
2cat << EOF
3This is a multi-line
4text block that will be
5printed as-is.
6EOF
7
8# Write to file
9cat << EOF > /tmp/config.yaml
10server:
11  port: 8080
12  host: localhost
13EOF

#Error Handling

bash
1#!/bin/bash
2set -e          # Exit on error
3set -u          # Error on undefined variable
4set -o pipefail # Pipe fails if any command fails
5
6# Combined (recommended)
7set -euo pipefail
8
9# Trap errors
10trap 'echo "Error on line $LINENO"; exit 1' ERR
11
12# Trap cleanup
13cleanup() {
14    echo "Cleaning up..."
15    rm -f /tmp/tempfile
16}
17trap cleanup EXIT
18
19# Check command success
20if ! command -v docker &>/dev/null; then
21    echo "Docker is not installed"
22    exit 1
23fi
24
25# Validate arguments
26if [ $# -lt 1 ]; then
27    echo "Usage: $0 <argument>"
28    exit 1
29fi

#Best Practices

#Script Template

bash
1#!/bin/bash
2set -euo pipefail
3
4# =============================================================================
5# Script: deploy.sh
6# Description: Deploy application to servers
7# Usage: ./deploy.sh <environment> [version]
8# =============================================================================
9
10# Constants
11readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12readonly LOG_FILE="/var/log/deploy.log"
13
14# Functions
15log() {
16    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
17}
18
19error() {
20    log "ERROR: $*" >&2
21    exit 1
22}
23
24usage() {
25    echo "Usage: $0 <environment> [version]"
26    echo "  environment: staging|production"
27    echo "  version: deployment version (default: latest)"
28    exit 1
29}
30
31cleanup() {
32    log "Cleaning up..."
33}
34
35# Main
36main() {
37    trap cleanup EXIT
38    
39    # Validate arguments
40    [[ $# -lt 1 ]] && usage
41    
42    local environment=$1
43    local version=${2:-latest}
44    
45    log "Deploying version $version to $environment"
46    
47    # Your deployment logic here
48    
49    log "Deployment complete!"
50}
51
52main "$@"

#Summary

ConceptExample
Variablesname="value"
Arguments$1, $2, $@
Conditionif [ -f file ]; then
Loopfor item in list; do
Functionfunc() { ... }
Error handlingset -euo pipefail

[!TIP] Pro Tip: Use ShellCheck to validate your scripts for common errors!