Linux Shell脚本自动化:从入门到精通实战指南
前言
在当今的IT运维和开发领域,自动化已经成为提高效率的关键。而Linux Shell脚本作为最基础且强大的自动化工具,掌握其精髓对于每个技术人员都至关重要。本文将深入探讨Shell脚本的实战应用,带你从基础入门到高级技巧,全面提升自动化运维能力。
Shell脚本基础核心概念
Shell环境与选择
在开始编写脚本前,我们需要了解不同的Shell环境。虽然bash是目前最流行的Shell,但还有其他选择:
#!/bin/bash
# 这是一个标准的bash脚本开头
#!/bin/zsh
# 或者使用zsh shell
#!/usr/bin/env bash
# 更通用的指定方式
变量与数据类型
Shell中的变量处理有其独特之处:
#!/bin/bash
# 定义变量
name="Shell Scripting"
version=1.0
# 只读变量
readonly MAX_RETRY=3
# 使用变量
echo "当前教程:$name 版本:$version"
# 命令替换
current_date=$(date +%Y-%m-%d)
echo "当前日期:$current_date"
条件判断与流程控制
条件判断是脚本逻辑的核心:
#!/bin/bash
# 数值比较
if [ $# -eq 0 ]; then
echo "请输入参数"
elif [ $# -gt 5 ]; then
echo "参数过多"
else
echo "参数数量合适"
fi
# 文件测试
file="/etc/passwd"
if [ -f "$file" ]; then
echo "$file 存在且是普通文件"
fi
# case语句
case $1 in
start)
echo "启动服务"
;;
stop)
echo "停止服务"
;;
*)
echo "用法: $0 {start|stop}"
;;
esac
高级Shell编程技巧
函数编程实践
函数让代码更加模块化和可重用:
#!/bin/bash
# 定义函数
log_message() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" >> /var/log/myscript.log
}
# 使用函数
log_message "INFO" "脚本开始执行"
# 带返回值的函数
check_disk_usage() {
local usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
echo $usage
}
disk_usage=$(check_disk_usage)
if [ $disk_usage -gt 90 ]; then
log_message "WARNING" "磁盘使用率超过90%"
fi
数组与关联数组
数组在数据处理中非常有用:
#!/bin/bash
# 普通数组
services=("nginx" "mysql" "redis")
echo "第一个服务: ${services[0]}"
# 遍历数组
for service in "${services[@]}"; do
echo "检查服务: $service"
systemctl status $service > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "$service 运行正常"
else
echo "$service 未运行"
fi
done
# 关联数组(bash 4.0+)
declare -A config
config["host"]="localhost"
config["port"]=3306
config["user"]="admin"
echo "数据库主机: ${config[host]}"
信号处理与错误处理
健壮的脚本需要良好的错误处理机制:
#!/bin/bash
set -euo pipefail # 严格模式
# 信号处理
trap 'cleanup' EXIT
trap 'echo "中断执行"; exit 1' INT TERM
cleanup() {
echo "执行清理操作..."
# 清理临时文件等
}
# 错误处理函数
handle_error() {
local line=$1
local command=$2
echo "错误发生在第 $line 行: $command"
exit 1
}
trap 'handle_error ${LINENO} "$BASH_COMMAND"' ERR
# 示例可能失败的操作
mkdir -p /tmp/test_dir
cd /tmp/test_dir || exit 1
实战案例:系统监控脚本
服务器健康检查
#!/bin/bash
set -euo pipefail
LOG_FILE="/var/log/server_health.log"
THRESHOLD_CPU=80
THRESHOLD_MEM=85
THRESHOLD_DISK=90
# 记录日志函数
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}
# 检查CPU使用率
check_cpu() {
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed 's/.*, *\([0-9.]*\)%* id.*/\1/' | awk '{print 100 - $1}')
if (( $(echo "$cpu_usage > $THRESHOLD_CPU" | bc -l) )); then
log "警告: CPU使用率 ${cpu_usage}% 超过阈值 ${THRESHOLD_CPU}%"
return 1
fi
log "CPU使用率正常: ${cpu_usage}%"
return 0
}
# 检查内存使用率
check_memory() {
local mem_info=$(free | grep Mem)
local total_mem=$(echo $mem_info | awk '{print $2}')
local used_mem=$(echo $mem_info | awk '{print $3}')
local mem_usage=$(echo "scale=2; $used_mem * 100 / $total_mem" | bc)
if (( $(echo "$mem_usage > $THRESHOLD_MEM" | bc -l) )); then
log "警告: 内存使用率 ${mem_usage}% 超过阈值 ${THRESHOLD_MEM}%"
return 1
fi
log "内存使用率正常: ${mem_usage}%"
return 0
}
# 检查磁盘空间
check_disk() {
local disk_usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $disk_usage -gt $THRESHOLD_DISK ]; then
log "警告: 磁盘使用率 ${disk_usage}% 超过阈值 ${THRESHOLD_DISK}%"
return 1
fi
log "磁盘使用率正常: ${disk_usage}%"
return 0
}
# 主监控函数
main() {
log "开始服务器健康检查"
check_cpu
check_memory
check_disk
log "健康检查完成"
}
# 执行主函数
main "$@"
自动化备份脚本
#!/bin/bash
set -euo pipefail
# 配置变量
BACKUP_DIR="/backup"
RETENTION_DAYS=7
DATE_FORMAT=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/backup_${DATE_FORMAT}.log"
# 需要备份的目录
BACKUP_SOURCES=(
"/etc"
"/home"
"/var/www"
)
# 数据库配置
DB_USER="backup_user"
DB_PASS="secure_password"
DB_NAME="important_db"
# 记录日志
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}
# 创建备份目录
create_backup_dir() {
local dir="${BACKUP_DIR}/${DATE_FORMAT}"
mkdir -p "$dir"
echo "$dir"
}
# 备份文件系统
backup_files() {
local backup_dir=$1
log "开始文件系统备份"
for source in "${BACKUP_SOURCES[@]}"; do
if [ -d "$source" ]; then
local target_name=$(basename "$source")
local backup_file="${backup_dir}/${target_name}_${DATE_FORMAT}.tar.gz"
log "备份: $source → $backup_file"
tar -czf "$backup_file" "$source" 2>> $LOG_FILE
if [ $? -eq 0 ]; then
log "成功备份: $source"
else
log "错误: 备份 $source 失败"
return 1
fi
else
log "警告: 备份源不存在: $source"
fi
done
}
# 备份数据库
backup_database() {
local backup_dir=$1
local db_file="${backup_dir}/database_${DATE_FORMAT}.sql.gz"
log "开始数据库备份"
if command -v mysqldump >/dev/null 2>&1; then
mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" | gzip > "$db_file" 2>> $LOG_FILE
if [ $? -eq 0 ]; then
log "数据库备份成功
> 评论区域 (0 条)_
发表评论