Shell脚本编程精要与高级实践
Shell脚本是自动化管理和执行任务的基础,通过掌握其语法和技巧,可以显著提高工作效率。
第一章:Shell脚本基础
1.1 变量操作
Shell变量无需预先声明,直接赋值即可。赋值时等号两侧不允许有空格。使用 $ 符号引用变量值。
# 定义一个名为 user 的变量
user="admin"
# 输出带变量的字符串
echo "当前用户是: $user"
1.2 条件判断
if 语句用于条件逻辑控制,结合各种测试运算符,如 -eq (等于)、-f (文件存在)。
# 检查用户ID是否大于等于1000
if [ $UID -ge 1000 ]; then
echo "普通用户"
else
echo "系统用户"
fi
1.3 循环结构
Shell脚本支持多种循环,如 for 和 while。下面是一个遍历文件列表的例子:
# 遍历当前目录下所有.txt文件
for file in *.txt; do
if [ -f "$file" ]; then
echo "找到文件: $file"
fi
done
1.4 常用命令组合
脚本常结合系统命令实现复杂功能。例如,检查特定进程是否运行:
| 命令 | 描述 |
|---|---|
ps aux |
列出所有正在运行的进程 |
grep |
搜索匹配模式的行 |
pgrep |
根据名称查找进程ID |
wc -l |
计算行数 |
结合使用 pgrep 和 wc -l 可以高效地判断一个服务是否在运行:
# 检查名为 nginx 的进程数量
process_count=$(pgrep nginx | wc -l)
if [ $process_count -gt 0 ]; then
echo "Nginx 进程正在运行..."
else
echo "Nginx 未运行。"
fi
第二章:进阶脚本编程
2.1 变量与环境变量
脚本内可定义局部变量,也可通过 export 命令导出为环境变量,供子进程使用。使用 env 或 printenv 查看当前环境变量。
# 定义一个本地变量
local_var="local_value"
# 导出为环境变量
export GLOBAL_VAR="global_value"
echo "本地变量: $local_var"
echo "全局变量: $GLOBAL_VAR"
2.2 控制流实践
除了 if,还可使用 case 语句处理多分支选择。循环结构支持 break 和 continue 来控制流程。
# 使用 case 处理不同操作
action="restart"
case $action in
start) echo "Starting...";;
stop) echo "Stopping...";;
restart) echo "Restarting...";;
*) echo "Unknown action";;
esac
2.3 命令替换与算术
命令替换 $(command) 用于获取命令输出。算术运算使用 $((expression))。
# 获取当前日期并格式化
backup_date=$(date +%Y%m%d)
echo "备份日期: $backup_date"
# 计算
num1=20
num2=5
result=$((num1 * num2))
echo "结果: $result"
2.4 IO重定向与管道
重定向(>, >>, <, 2>)用于改变输入输出流。管道(|)将一个命令的输出连接到另一个命令的输入。
# 将标准输出和错误输出分别重定向
ls -l /nonexistent_dir > list.txt 2> error.log
# 使用管道处理文本
dmesg | grep -i "error" | tail -n 5
2.5 参数处理
脚本参数可通过 $1, $2... 访问。$@ 代表所有参数,$# 代表参数个数。getopts 用于更复杂的选项解析。
# 简单参数处理
echo "脚本名: $0"
echo "第一个参数: $1"
echo "参数总数: $#"
# 使用 getopts 解析选项
while getopts ":f:v" opt; do
case $opt in
f) file="$OPTARG" ;;
v) verbose=true ;;
\?) echo "Invalid option: -$OPTARG" >&2 ;;
esac
done
shift $((OPTIND-1)) # 移除已处理的选项
echo "输入文件: $file"
if [ "$verbose" = true ]; then
echo "详细模式已开启"
fi
第三章:高级特性与调试
3.1 函数封装
函数用于组织代码块,提高复用性。函数参数通过位置变量 $1, $2... 传递,返回值通常通过退出状态码($?)或标准输出。
# 定义一个计算目录大小的函数
get_dir_size() {
local dir_path=$1
if [ -d "$dir_path" ]; then
du -sh "$dir_path" | awk '{print $1}'
else
echo "0K"
fi
}
# 调用函数
size=$(get_dir_size "/var/log")
echo "日志目录大小: $size"
3.2 信号处理
trap 命令允许脚本响应系统信号(如中断)。
# 清理函数
cleanup() {
echo "正在清理临时文件..."
rm -f /tmp/temp_data.tmp
echo "清理完成."
}
# 捕获 INT (Ctrl+C) 和 TERM 信号
trap cleanup INT TERM
# 模拟脚本运行
echo "脚本正在运行,按 Ctrl+C 退出..."
touch /tmp/temp_data.tmp
sleep infinity
3.3 调试技巧
使用 set -x 启用脚本执行跟踪,打印每条命令及其参数。set -e 使脚本在命令失败时立即退出。
#!/bin/bash
set -x # 开启调试模式
set -e # 发生错误时退出
echo "开始执行任务..."
# ... 实际命令 ...
ls -l /nonexistent_file # 故意制造错误
echo "任务完成。" # 这行不会被执行
第四章:实战场景
4.1 服务管理脚本
编写用于启动、停止和管理后台服务的脚本,通常放在 /etc/init.d/ 或使用 systemd 服务单元。
# /etc/init.d/mydaemon 脚本示例
# ... (start, stop, status 逻辑) ...
4.2 定时任务自动化
使用 cron 调度脚本执行周期性任务,如备份、日志轮转。
# crontab 条目示例:每天凌晨3点执行备份脚本
0 3 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
4.3 日志分析
脚本可用于批量处理日志文件,提取关键信息,生成报告。
# 统计 Nginx 访问日志中的 404 错误
grep " 404 " /var/log/nginx/access.log | awk '{print $7, $1}' | sort | uniq -c | sort -nr
4.4 资源监控
编写脚本定期检查系统资源(CPU, 内存, 磁盘),并在超出阈值时触发告警。
# 检查磁盘使用率
disk_usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
threshold=90
if [ "$disk_usage" -gt "$threshold" ]; then
echo "警告:磁盘使用率已达 ${disk_usage}%" | mail -s "磁盘空间不足警告" admin@example.com
fi
第五章:总结
Shell脚本是系统管理和自动化不可或缺的工具。熟练掌握变量、控制流、函数、信号处理和调试技巧,能有效应对各种运维挑战。随着容器化和云原生技术的发展,Shell脚本在DevOps流程中依然扮演着重要角色,用于编排、配置和管理自动化流水线。