9.4. Generating Reports#
9.4.1. Common Pitfalls#
1. Using echo instead of printf for formatted output
# Less control with echo
echo "Name: $name, Age: $age"
# Better: printf for precise formatting
printf "Name: %-20s Age: %3d\n" "$name" "$age"
2. Not including timestamps in logs
# Bad: hard to track when events occurred
echo "Error occurred" >> app.log
# Good: timestamp helps debugging
echo "$(date '+%Y-%m-%d %H:%M:%S') Error occurred" >> app.log
3. Mixing stdout and stderr in the same file without distinction
# Hard to separate errors from normal output
command > all_output.log 2>&1
# Better: keep them separate initially
command > output.log 2> errors.log
4. Forgetting to handle log rotation
# Bad: log grows unbounded
echo "Message" >> app.log
# Better: rotate when size limit reached
# Or use logrotate utility with proper configuration
9.4.2. Building Complex Reports#
9.4.2.1. Multi-Section Report Generation#
#!/bin/bash
# Generate comprehensive system report
generate_system_report() {
local report_file=$1
local report_date=$(date '+%Y-%m-%d %H:%M:%S')
{
# Title section
printf "\n"
printf "%-60s\n" "============ SYSTEM REPORT ============"
printf "%-60s\n" "Generated: $report_date"
printf "%-60s\n" "Host: $(hostname)"
printf "%-60s\n" "======================================="
# Hardware section
printf "\n%-20s\n" "=== HARDWARE ==="
printf "%-15s : %s\n" "CPU Model" "$(lscpu | grep 'Model name' | cut -d: -f2-)"
printf "%-15s : %d cores\n" "CPU Count" "$(nproc)"
printf "%-15s : %s\n" "Total Memory" "$(free -h | awk 'NR==2 {print $2}')"
# Disk section
printf "\n%-20s\n" "=== DISK USAGE ==="
printf "%-20s %-10s %-10s %s\n" "Filesystem" "Size" "Used" "Percent"
df -h | tail -n +2 | awk '{printf "%-20s %-10s %-10s %s\n", $1, $2, $3, $5}'
# Process section
printf "\n%-20s\n" "=== TOP PROCESSES ==="
printf "%-8s %-8s %-15s %s\n" "PID" "CPU" "MEMORY" "COMMAND"
ps aux | sort -k3 -rn | head -5 | awk '{printf "%-8s %-8s %-15s %s\n", $2, $3, $4, $11}'
printf "\n%-60s\n" "======================================="
} | tee "$report_file"
}
generate_system_report system_report.txt
9.4.3. Generating CSV and Tabular Data#
9.4.3.1. Creating CSV Output#
#!/bin/bash
# Export data to CSV
export_users_csv() {
local output=$1
{
# Header
printf "username,uid,shell\n"
# Data rows (from /etc/passwd)
awk -F: '{printf "%s,%d,%s\n", $1, $3, $7}' /etc/passwd
} > "$output"
}
# Usage
export_users_csv users.csv
9.4.3.2. Creating Formatted Tables#
#!/bin/bash
# Generate a process table
generate_process_table() {
local output=$1
{
# Header with alignment
printf "%-8s %-8s %-10s %8s\n" "PID" "USER" "COMMAND" "MEMORY"
printf "%-8s %-8s %-10s %8s\n" "---" "----" "-------" "------"
# Process data
ps aux | sort -k6 -rn | head -10 | \
awk '{printf "%-8s %-8s %-10s %8s\n", $2, $1, $11, $6}'
} > "$output"
}
generate_process_table process_report.txt
9.4.4. Creating Structured Logs#
9.4.4.1. Log File Management#
#!/bin/bash
LOG_DIR="/var/log/myapp"
LOG_FILE="$LOG_DIR/app.log"
ERROR_LOG="$LOG_DIR/app.err"
# Initialize logging
setup_logging() {
mkdir -p "$LOG_DIR"
touch "$LOG_FILE" "$ERROR_LOG"
}
# Log function with timestamp
log() {
local level=$1
shift
local message=$*
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case $level in
INFO)
echo "[$timestamp] INFO: $message" >> "$LOG_FILE"
;;
ERROR)
echo "[$timestamp] ERROR: $message" | tee -a "$ERROR_LOG" >&2
;;
WARN)
echo "[$timestamp] WARN: $message" >> "$LOG_FILE"
;;
esac
}
# Usage
setup_logging
log INFO "Application started"
log WARN "This is a warning"
log ERROR "An error occurred"
9.4.4.2. Log Rotation#
#!/bin/bash
# Rotate logs when they exceed size limit
rotate_logs() {
local log_file=$1
local max_size=$((10 * 1024 * 1024)) # 10MB
if [[ -f "$log_file" ]] && [[ $(stat -c%s "$log_file") -gt $max_size ]]; then
local timestamp=$(date +%Y%m%d_%H%M%S)
mv "$log_file" "${log_file}.${timestamp}"
gzip "${log_file}.${timestamp}"
touch "$log_file"
fi
}
rotate_logs /var/log/myapp/app.log
9.4.5. Structured Output Formatting#
9.4.5.1. Using printf for Precise Formatting#
# Basic formatting
printf "Name: %s, Age: %d\n" "Alice" 30
# Column alignment
printf "%-15s %10s %8s\n" "Item" "Quantity" "Price"
printf "%-15s %10d %8.2f\n" "Apple" 5 1.50
printf "%-15s %10d %8.2f\n" "Banana" 3 0.75
# Padding and alignment options
printf "%5d\n" 42 # Right-align in 5-char width
printf "%-5d\n" 42 # Left-align in 5-char width
printf "%05d\n" 42 # Zero-padded to 5 chars
# Floating point precision
printf "%.2f\n" 3.14159 # 2 decimal places
printf "%8.2f\n" 3.14159 # 8-char width, 2 decimals
9.4.5.2. Creating Formatted Reports#
#!/bin/bash
# Generate a system report
generate_report() {
local output_file=$1
{
printf "====================================\n"
printf "%-20s %s\n" "System Report" "$(date)"
printf "====================================\n\n"
printf "%-20s %s\n" "Hostname:" "$(hostname)"
printf "%-20s %s\n" "Kernel:" "$(uname -r)"
printf "%-20s %d\n" "CPU Cores:" "$(nproc)"
printf "%-20s %s\n" "Disk Usage:" "$(df -h / | awk 'NR==2 {print $5}')"
printf "%-20s %s\n" "Memory Usage:" "$(free -h | awk 'NR==2 {print $3 "/" $2}')"
printf "\n====================================\n"
} | tee "$output_file"
}
generate_report system_report.txt