资讯动态

Shell脚本编程从入门到实战:自动化运维必备技能

发布时间:2026/9/14 9:11:45 来源:尧图企业网站定制
1. Shell编程入门概述Shell脚本是Linux/Unix系统管理员和开发人员的必备技能。它允许我们通过编写简单的文本文件来自动化重复性任务将复杂的命令行操作封装成可重复执行的程序。与编译型语言不同Shell脚本是解释执行的这使得它特别适合系统管理、文件操作和快速原型开发。我在十多年的运维工作中Shell脚本帮我完成了90%的日常系统管理工作。从简单的日志清理到复杂的部署流程一个精心编写的脚本可以节省大量时间。对于初学者来说Shell脚本的优势在于无需复杂开发环境任何文本编辑器都能编写直接调用系统命令学习曲线平缓即时测试即时生效调试周期短2. 基础语法精要2.1 脚本结构解析每个Shell脚本都应该以shebang开头#!/bin/bash # 这是注释 echo Hello World第一行指定解释器路径#开头的行是注释。保存为hello.sh后需要添加执行权限chmod x hello.sh ./hello.sh2.2 变量操作技巧变量定义和使用时注意namevalue # 等号两边不能有空格 echo $name # 使用变量要加$ echo ${name} # 推荐这种写法明确变量边界重要细节变量默认都是字符串类型局部变量用local声明函数内使用readonly声明常量特殊变量$0(脚本名)$1(第一个参数)$#(参数个数)3. 流程控制实战3.1 条件判断进阶if语句的三种形式# 基本形式 if [ condition ]; then commands fi # 带else if [ -f /path/file ]; then echo 文件存在 else echo 文件不存在 fi # 多条件 if [[ $var -gt 10 ]]; then echo 大于10 elif [[ $var -lt 5 ]]; then echo 小于5 else echo 5到10之间 fi测试文件常用选项-e文件存在-f是普通文件-d是目录-r可读-w可写-x可执行3.2 循环结构优化for循环的几种写法# 传统C风格 for ((i0; i10; i)); do echo $i done # 遍历列表 for color in red green blue; do echo $color done # 遍历命令输出 for file in $(ls *.txt); do echo 处理文件: $file donewhile循环示例count1 while [ $count -le 5 ]; do echo 计数: $count ((count)) done4. 函数与错误处理4.1 函数编写规范定义和使用函数function log_message { local timestamp$(date %Y-%m-%d %H:%M:%S) echo [$timestamp] $1 /var/log/myscript.log } log_message 脚本开始执行最佳实践函数名使用小写加下划线用local声明局部变量通过$1$2获取参数$表示所有参数return只能返回数字(0-255)4.2 错误处理机制# 检查上条命令是否成功 if ! mkdir /tmp/mydir; then echo 创建目录失败 2 exit 1 fi # 设置错误退出 set -euo pipefail # -e: 命令失败立即退出 # -u: 使用未定义变量报错 # -o pipefail: 管道中任意命令失败则整个管道失败 # 捕获信号 trap cleanup; exit SIGINT SIGTERM5. 文本处理三剑客5.1 grep高效搜索# 基本搜索 grep pattern file.txt # 常用选项 grep -i error /var/log/syslog # 忽略大小写 grep -v debug app.log # 反向匹配 grep -r function /src # 递归搜索 grep -A3 -B2 exception log.txt # 显示匹配前后行5.2 sed流编辑器# 替换文本 sed s/old/new/g input.txt # 直接修改文件 sed -i.bak s/foo/bar/ file.txt # 删除行 sed /pattern/d file.txt # 多重操作 sed -e s/a/A/g -e s/b/B/g file.txt5.3 awk数据处理# 打印特定列 awk {print $1,$3} data.txt # 条件过滤 awk $3 100 {print $0} sales.csv # 使用分隔符 awk -F: {print $1,$6} /etc/passwd # 计算统计 awk {sum$3} END {print sum} data.txt6. 实用脚本案例6.1 日志分析脚本#!/bin/bash # 分析Nginx日志获取访问量前10的IP LOG_FILE/var/log/nginx/access.log OUTPUT_FILE/tmp/top_ips.txt if [ ! -f $LOG_FILE ]; then echo 错误: 日志文件不存在 2 exit 1 fi echo Top 10访问IP: $OUTPUT_FILE awk {print $1} $LOG_FILE | sort | uniq -c | sort -nr | head -10 $OUTPUT_FILE echo 分析完成结果保存在 $OUTPUT_FILE6.2 系统监控脚本#!/bin/bash # 监控系统资源使用情况 ALERT_THRESHOLD90 EMAILadminexample.com check_disk() { local usage$(df -h | awk $NF/{print $5} | tr -d %) if [ $usage -gt $ALERT_THRESHOLD ]; then echo 磁盘使用率过高: $usage% | mail -s 磁盘警报 $EMAIL fi } check_memory() { local free$(free -m | awk /Mem/{printf %.0f, $3/$2*100}) if [ $free -gt $ALERT_THRESHOLD ]; then echo 内存使用率过高: $free% | mail -s 内存警报 $EMAIL fi } check_disk check_memory7. 调试与优化技巧7.1 脚本调试方法# 打印执行命令 set -x # 你的脚本代码 set x # 另一种方式 bash -x script.sh # 检查语法而不执行 bash -n script.sh # 使用trap调试 trap echo 在行 $LINENO: var$var DEBUG7.2 性能优化建议减少子进程创建# 不好: 每次循环都调用date for i in {1..100}; do echo $(date) done # 更好: 只调用一次date now$(date) for i in {1..100}; do echo $now done使用内置字符串操作代替外部命令# 不好 filename$(echo $fullpath | awk -F/ {print $NF}) # 更好 filename${fullpath##*/}大量文本处理时考虑使用awk代替多个grep/sed组合8. 安全注意事项8.1 安全编程实践总是验证用户输入read -p 输入目录: dir if [ ! -d $dir ]; then echo 错误: 目录不存在 2 exit 1 fi避免使用eval# 危险! eval $user_input # 应该使用数组安全执行 cmd(ls -l $dir) ${cmd[]}设置安全的默认权限umask 077 # 创建的文件默认600目录7008.2 常见陷阱未引用的变量# 如果文件名包含空格会出问题 for file in $(ls); do rm $file done # 正确做法 for file in *; do rm $file done管道中的错误被忽略# 即使failcmd失败echo也会执行 failcmd | echo 继续执行 # 正确做法 set -o pipefail failcmd | echo 现在会捕获错误整数比较错误# 字符串比较 if [ 10 \ 2 ]; then echo 10比2小 fi # 正确整数比较 if (( 10 2 )); then echo 这不会执行 fi9. 进阶技巧9.1 数组和关联数组# 普通数组 colors(red green blue) echo ${colors[1]} # 输出green colors(yellow) # 添加元素 # 关联数组(Bash 4) declare -A user user[name]Alice user[age]25 echo ${user[name]}9.2 进程替换# 比较两个命令的输出 diff (ls dir1) (ls dir2) # 避免创建临时文件 paste (cut -f1 file1) (cut -f3 file2)9.3 并行处理# 使用后台执行 for url in ${urls[]}; do wget $url done wait # 等待所有后台任务完成 # 使用xargs并行 printf %s\n ${files[]} | xargs -P4 -I{} process_file {}10. 跨平台兼容性10.1 避免bashism如果脚本需要跨平台运行避免使用Bash特有特性# 使用POSIX test而不是[[ ]] if [ $var -gt 10 ]; then # 使用printf代替echo -e printf Line1\nLine2\n # 避免使用数组改用空格分隔字符串 filesfile1 file2 file3 for file in $files; do [ -f $file ] || continue # 处理文件 done10.2 检测运行环境#!/bin/sh # 检测Bash版本 if [ -n $BASH_VERSION ]; then echo 运行在Bash $BASH_VERSION else echo 警告: 建议使用Bash执行此脚本 2 fi # 检查工具是否存在 check_command() { if ! command -v $1 /dev/null 21; then echo 错误: $1 命令未找到 2 exit 1 fi } check_command awk check_command sed11. 代码组织与维护11.1 模块化设计将常用功能分离到单独文件# lib/utils.sh log_info() { echo [INFO] $(date %F %T) - $* } # main.sh source $(dirname $0)/lib/utils.sh log_info 脚本启动11.2 文档规范在脚本头部添加标准文档#!/bin/bash # 名称: 系统备份脚本 # 描述: 自动备份指定目录到远程服务器 # 作者: Your Name # 版本: 1.0 # 用法: ./backup.sh [选项] 目录 # 选项: # -c 启用压缩 # -v 详细输出11.3 版本控制建议将脚本纳入Git管理# .gitignore *.tmp *.log12. 实战项目自动化部署脚本#!/bin/bash set -euo pipefail # 配置 APP_NAMEmyapp APP_DIR/opt/$APP_NAME BACKUP_DIR/var/backups/$APP_NAME REPO_URLgitexample.com:myrepo.git BRANCHproduction # 初始化目录 init_dirs() { mkdir -p $BACKUP_DIR mkdir -p $APP_DIR } # 备份当前版本 backup_current() { local timestamp$(date %Y%m%d%H%M%S) tar -czf $BACKUP_DIR/$timestamp.tar.gz -C $APP_DIR . } # 部署新版本 deploy() { cd $APP_DIR if [ -d .git ]; then git fetch origin git checkout $BRANCH git reset --hard origin/$BRANCH else git clone $REPO_URL . git checkout $BRANCH fi } # 重启服务 restart_service() { systemctl restart ${APP_NAME}.service } # 主流程 main() { echo 开始部署 $APP_NAME init_dirs backup_current deploy restart_service echo 部署成功完成 } main $

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价