Kuasai bash scripting dengan variabel, functions, control flow, dan error handling. Bangun script tingkat produksi untuk DevOps dan otomasi.

Selamat datang di episode final dari seri Linux Mastery. Kami telah membahas:
Sekarang kami menyatukannya dengan bash scripting mastery.
Bash scripting adalah tempat Linux menjadi powerful. Ini adalah cara Anda:
Dalam episode ini, kami akan mempelajari cara menulis script bash tingkat produksi yang robust, maintainable, aman, dan efisien.
Setiap script produksi harus mengikuti struktur konsisten:
#!/bin/bash
################################################################################
# Script: backup_database.sh
# Description: Backs up the application database daily
# Author: DevOps Team
# Version: 1.0
################################################################################
set -euo pipefail # Exit on error, undefined variables, pipe failures
# Configuration
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly LOG_FILE="/var/log/backup.log"
readonly BACKUP_DIR="/var/backups/database"
readonly RETENTION_DAYS=30
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly NC='\033[0m'
################################################################################
# Functions
################################################################################
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
error() {
echo -e "${RED}[ERROR]${NC} $*" >&2
exit 1
}
success() {
echo -e "${GREEN}[SUCCESS]${NC} $*"
}
################################################################################
# Main Script
################################################################################
main() {
log "Starting database backup..."
# Your script logic here
success "Backup completed successfully"
}
main "$@"# Deklarasi variabel
NAME="Alice"
AGE=30
FRUITS=("apple" "banana" "orange")
# Akses variabel
echo $NAME
echo ${NAME}
# Variabel read-only
readonly API_KEY="secret123"
# Variabel default
echo ${NAME:-"default"}
# Panjang string
echo ${#NAME}
# Substring
echo ${NAME:0:3}
# Replace
echo ${NAME/Alice/Bob}# Simple if
if [ "$AGE" -gt 18 ]; then
echo "Adult"
fi
# If-else
if [ "$AGE" -gt 18 ]; then
echo "Adult"
else
echo "Minor"
fi
# If-elif-else
if [ "$AGE" -lt 13 ]; then
echo "Child"
elif [ "$AGE" -lt 18 ]; then
echo "Teenager"
else
echo "Adult"
fi| Operator | Meaning |
|---|---|
-eq | Equal (numeric) |
-ne | Not equal (numeric) |
-lt | Less than |
-gt | Greater than |
= | Equal (string) |
!= | Not equal (string) |
-z | String is empty |
-f | File exists |
-d | Directory exists |
-r | File is readable |
-w | File is writable |
-x | File is executable |
# For loop
for fruit in apple banana orange; do
echo "Fruit: $fruit"
done
# For loop over array
COLORS=("red" "green" "blue")
for color in "${COLORS[@]}"; do
echo "Color: $color"
done
# C-style loop
for ((i=1; i<=5; i++)); do
echo "Number: $i"
done
# While loop
COUNT=1
while [ "$COUNT" -le 5 ]; do
echo "Count: $COUNT"
((COUNT++))
done
# Read file line by line
while IFS= read -r line; do
echo "Line: $line"
done < file.txtcase "$1" in
start)
echo "Starting service..."
;;
stop)
echo "Stopping service..."
;;
restart)
echo "Restarting service..."
;;
*)
echo "Unknown command: $1"
exit 1
;;
esac# Function definition
my_function() {
local first_param="$1"
local second_param="$2"
echo "First: $first_param"
echo "Second: $second_param"
return 0 # Success
}
# Call function
my_function "arg1" "arg2"
# Function dengan return value
get_greeting() {
echo "Hello, $1!"
}
greeting=$(get_greeting "Alice")
echo "$greeting"
# Recursive function
factorial() {
local n=$1
if [ "$n" -le 1 ]; then
echo 1
else
local prev=$((n - 1))
local prev_result=$(factorial "$prev")
echo $((n * prev_result))
fi
}
result=$(factorial 5)
echo "5! = $result"# Read user input
read -p "Enter your name: " name
echo "Hello, $name"
# Read with timeout
read -t 5 -p "Enter something (5 seconds): " input
# Read password (hidden)
read -sp "Enter password: " password
# Command-line arguments
echo "Script name: $0"
echo "First argument: $1"
echo "All arguments: $@"
echo "Number of arguments: $#"
# Process arguments with getopts
while getopts "hv:d:" opt; do
case $opt in
h) echo "Usage: $0 [-h] [-v level] [-d dir]"; exit 0 ;;
v) VERBOSE="$OPTARG" ;;
d) DIRECTORY="$OPTARG" ;;
esac
done# Test if file exists
if [ -e "$FILE" ]; then
echo "File exists"
fi
# Test if regular file
if [ -f "$FILE" ]; then
echo "Is a regular file"
fi
# Test if directory
if [ -d "$DIR" ]; then
echo "Is a directory"
fi
# Read file line by line
while IFS= read -r line; do
echo "Line: $line"
done < file.txt
# Write to file
echo "Hello" > file.txt
echo "World" >> file.txt
# Write multiple lines
cat > file.txt << EOF
Line 1
Line 2
Line 3
EOF# Indexed array
FRUITS=("apple" "banana" "orange")
echo "${FRUITS[0]}" # apple
echo "${FRUITS[@]}" # all elements
echo "${#FRUITS[@]}" # length
# Add element
FRUITS+=("grape")
# Loop over array
for fruit in "${FRUITS[@]}"; do
echo "$fruit"
done
# Associative array
declare -A PERSON
PERSON[name]="Alice"
PERSON[age]="30"
echo "${PERSON[name]}"# String length
str="Hello"
echo "${#str}" # 5
# Substring
echo "${str:0:3}" # Hel
# Remove prefix
str="prefix_value"
echo "${str#prefix_}" # value
# Remove suffix
str="value_suffix"
echo "${str%_suffix}" # value
# Replace
str="hello world"
echo "${str/world/universe}" # hello universe
# Replace all
str="aaa"
echo "${str//a/b}" # bbb# Arithmetic expansion
result=$((2 + 3))
echo "$result" # 5
# Increment
((count++))
((count += 5))
# Arithmetic in conditions
if ((count > 10)); then
echo "Count is greater than 10"
fi
# Floating point (use bc)
result=$(echo "scale=2; 10 / 3" | bc)
echo "$result" # 3.33#!/bin/bash
# Exit on error
set -e
# Exit on undefined variable
set -u
# Exit on pipe failure
set -o pipefail
# Trap errors
trap 'echo "Error on line $LINENO"; exit 1' ERR
# Check command success
if ! command -v docker &> /dev/null; then
echo "Docker is not installed"
exit 1
fi
# Debug mode
set -x # Print commands as executed
set +x # Turn off debug
# Logging
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}
error() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $*" >&2
exit 1
}#!/bin/bash
check_cpu() {
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print int($2)}')
echo "CPU Usage: ${cpu_usage}%"
if [ "$cpu_usage" -gt 80 ]; then
echo "WARNING: CPU usage is high!"
fi
}
check_memory() {
local mem_usage=$(free | grep Mem | awk '{printf("%.0f", $3/$2 * 100)}')
echo "Memory Usage: ${mem_usage}%"
if [ "$mem_usage" -gt 80 ]; then
echo "WARNING: Memory usage is high!"
fi
}
check_disk() {
local disk_usage=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
echo "Disk Usage: ${disk_usage}%"
if [ "$disk_usage" -gt 80 ]; then
echo "WARNING: Disk usage is high!"
fi
}
main() {
echo "=== System Monitoring Report ==="
echo "Time: $(date)"
check_cpu
check_memory
check_disk
}
main "$@"#!/bin/bash
set -euo pipefail
readonly BACKUP_DIR="/var/backups/database"
readonly DB_NAME="myapp"
readonly RETENTION_DAYS=30
backup_database() {
local backup_file="$BACKUP_DIR/${DB_NAME}_$(date +%Y%m%d_%H%M%S).sql.gz"
echo "Starting backup of $DB_NAME..."
if mysqldump "$DB_NAME" | gzip > "$backup_file"; then
echo "Backup completed: $backup_file"
else
echo "Backup failed" >&2
return 1
fi
}
cleanup_old_backups() {
echo "Cleaning up backups older than $RETENTION_DAYS days..."
find "$BACKUP_DIR" -name "${DB_NAME}_*.sql.gz" -mtime "+$RETENTION_DAYS" -delete
}
main() {
mkdir -p "$BACKUP_DIR"
backup_database
cleanup_old_backups
echo "Backup process completed"
}
main "$@"# Validate input
validate_path() {
local path="$1"
if [ -z "$path" ]; then
echo "Error: Path cannot be empty"
return 1
fi
if [[ "$path" =~ [^a-zA-Z0-9._/-] ]]; then
echo "Error: Invalid characters in path"
return 1
fi
return 0
}
# Secure file handling
temp_file=$(mktemp)
trap "rm -f $temp_file" EXIT
# Set restrictive permissions
touch sensitive_file.txt
chmod 600 sensitive_file.txt
# Avoid injection attacks
# DON'T: eval "command $user_input"
# DO: command "$user_input"
# DON'T: rm $file_to_delete
# DO: rm "$file_to_delete"# DON'T: Unquoted variables
FILE=my file.txt
cat $FILE # Tries to open "my" and "file.txt"
# DO: Quote variables
FILE="my file.txt"
cat "$FILE"
# DON'T: Missing error handling
cd /nonexistent
rm -rf * # Deletes current directory!
# DO: Check for errors
cd /nonexistent || exit 1
rm -rf *
# DON'T: Hardcoded values
BACKUP_DIR="/var/backups"
# DO: Use configuration
BACKUP_DIR="${BACKUP_DIR:-/var/backups}"# Manual testing
./script.sh arg1 arg2
# Test with edge cases
./script.sh ""
./script.sh "special chars !@#$%"
# Use shellcheck to lint
shellcheck script.sh
# Format with shfmt
shfmt -i 2 -w script.shGunakan Bash untuk: Script sederhana, otomasi, tugas satu kali
Gunakan Python untuk: Logika kompleks, struktur data, aplikasi besar
Gunakan Go untuk: Performa tinggi, alat sistem, deployment single binary
Anda telah menyelesaikan seri Linux Mastery:
Dokumentasi Resmi
Learning Resources
Tools dan Utilities
Penguasaan Linux adalah perjalanan, bukan tujuan. Skill yang Anda pelajari dalam seri ini adalah fondasi. Pembelajaran nyata terjadi ketika Anda menerapkan konsep ini pada masalah dunia nyata.
Baik Anda mengejar karir di DevOps, cloud engineering, SRE, atau software engineering, Linux adalah fondasi. Kuasai itu, dan Anda akan tak terkalahkan.
Terus belajar. Terus membangun. Terus mengotomatisasi.
Selamat datang di komunitas Linux.