Shell 脚本从入门到实战条件判断 循环全套通关指南 本文素材来源于运维课堂笔记适合 Linux 初学者、运维新手吃透 if / 函数 /case/while/until/for/select写运维脚本不再头疼。引言作为 Linux 运维Shell 脚本是我们日常工作的神兵利器。服务监控、批量创建账号、日志分析、定时告警、批量备份几乎所有重复的工作都可以交给 Shell 脚本完成。写脚本核心两大模块条件判断和循环语句。条件满足什么条件做什么事if、case、函数循环重复执行一段逻辑while、until、for、select很多新手写脚本踩坑括号忘记空格、分不清return和exit、管道 while 子进程问题、case 忘记双分号。本文把语法、示例、企业案例、经典练习题、避坑点一次性讲清楚。一、if 条件判断语句if 是使用频率最高的条件语句几乎所有判断都能用 if 实现。1.1 三种语法结构✅ 单分支满足条件就执行if 条件表达式;then 执行命令 fi✅ 双分支二选一if 条件表达式;then 条件成立执行 else 条件不成立执行 fi✅ 多分支多组判断if 条件1;then 命令1 elif 条件2;then 命令2 else 都不满足执行 fi小提示elif后面必须带thenelse后面不能写 then。1.2 5 种条件表达式写法表格表达式适用场景test 表达式老式写法等价于 [][ 表达式 ]字符串、文件测试括号内侧必须留空格[[ 表达式 ]]增强字符串支持正则~((算术表达式))只做整数运算比较不需要空格直接写命令利用命令$?返回值做判断极简示例监控 sshd 服务#!/bin/bash # 检测sshd挂掉自动启动 systemctl is-active sshd /dev/null if [ $? -ne 0 ];then echo sshd未运行正在启动... systemctl start sshd else echo sshd运行正常 fi小提示systemctl is-active返回值可以直接作为 if 条件简化写法if systemctl is-active sshd /dev/null;then echo sshd运行中 fiif 企业实战检测服务端口#!/bin/bash if ss -lnt | grep -q :3306;then echo Mysql 3306端口监听正常 else echo Mysql未启动 fi二、Shell 函数函数把重复代码封装起来实现代码复用模块化开发。2.1 三种定义语法#写法1 完整写法 function hello () { echo hello world } #写法2 省略括号 function hello { echo hello world } #写法3 省略function最常用 hello () { echo hello world }2.2 核心要点 坑点必须先定义后调用调用的时候只写函数名不要加括号return n退出函数返回状态码exit n直接退出整个脚本local定义函数内部局部变量不加 local 变量全局生效函数可以接收位置参数$1 $2 $# $$0永远是脚本名字不是函数名函数可以单独放到文件使用source 文件名加载函数库极简示例带参数彩色打印函数#!/bin/bash print_color(){ if [ $1 PASS ];then echo -e \033[1;32mPASS\033[0m elif [ $1 FAIL ];then echo -e \033[1;31mFAIL\033[0m fi } #调用 print_color PASS print_color FAIL小提示递归不要滥用著名 fork 炸弹:(){ :|: };:无限生成进程耗尽系统资源可以用ulimit -u 最大进程数防护。企业实战模板函数封装 url 检测#!/bin/bash usage(){ echo 用法 $0 网址 exit 1 } check_url(){ wget --spider -q -T5 $1 [ $? -eq 0 ] echo $1 访问正常 || echo $1 访问失败 } main(){ [ $# -ne 1 ] usage check_url $1 } main $*三、case 条件语句case 是多分支判断适合固定字符串匹配常用于服务启停脚本等价于一堆elif代码更整洁。3.1 语法格式case $变量 in 值1) 命令 ;; 值2|值3) # 多个值匹配同一个逻辑 命令 ;; *) # 相当于else所有其他情况 默认执行命令 ;; esac小提示每个分支结尾;;千万不要漏掉esac是 case 反过来写代表语句结束。极简示例sshd 启停脚本#!/bin/bash case $1 in start) systemctl start sshd ;; stop) systemctl stop sshd ;; restart|reload) systemctl restart sshd ;; status) systemctl status sshd ;; *) echo 用法$0 start|stop|restart|reload|status ;; esac企业实战user‑mgr 用户管理脚本核心片段功能增删查用户使用chattr锁定配置文件防止篡改#!/bin/bash [ $UID -ne 0 ] echo 请root运行 exit 1 users_file/etc/users [ -f ${users_file} ] || touch ${users_file} action$1 username$2 case $action in -s|--search) if grep -q username: $username $users_file;then echo $username 用户存在 else echo $username 用户不存在 fi ;; -a|--add) chattr -i $users_file echo username: $username $users_file chattr i $users_file echo 添加用户成功 ;; -d|--del) chattr -i $users_file sed -i /username: $username/d $users_file chattr i $users_file echo 删除用户成功 ;; *) echo 用法 $0 [-a|-d|-s] username ;; esac四、while 和 until 循环while当型循环条件为 true就一直执行循环体非常适合做守护进程、死循环监控。while 条件;do 循环体命令 doneuntil直到型循环条件为 false 才执行循环条件成立就退出和 while 逻辑相反日常使用较少。until 条件;do 循环体命令 done小提示while true/until false实现无限死循环生产环境死循环一定要加sleep避免 CPU 跑满。极简示例 1while 实现 5 到 1 倒序输出#!/bin/bash i5 while ((i0));do echo $i ((i--)) done极简示例 2until 实现 5 到 1 倒序输出#!/bin/bash i5 until ((i0));do echo $i ((i--)) done经典练习题猴子吃桃子猴子第一天摘一堆桃子每天吃一半多一个第 10 天只剩 1 个求第一天桃子总数#!/bin/bash today1 i1 while ((i9));do lastday$[(today1)*2] today$lastday ((i)) done echo 第一天桃子总数$today小提示while 读取文件 4 种写法推荐写法#!/bin/bash while read line;do echo $line done /etc/hosts坑cat /etc/hosts | while read line管道会产生子进程循环内部变量外部无法获取企业实战 1守护进程监控 sshd5 秒检测一次#!/bin/bash while true;do systemctl is-active sshd /dev/null if [ $? -ne 0 ];then systemctl restart sshd /dev/null echo sshd异常已重启 fi sleep 5 done企业实战 2根据网络连接数封禁攻击 IP简化版#!/bin/bash while true;do ss -t | grep ESTAB | awk {print $4} | cut -d: -f1 | sort | uniq -c /tmp/tmp.log exec /tmp/tmp.log while read count ip;do if [ $count -gt 100 ] ! iptables -L -n | grep -q $ip;then iptables -I INPUT -s $ip -j DROP echo $ip 已封禁 /tmp/drop.log fi done sleep 10 done补充后台任务小知识点脚本.sh 放到后台运行nohup 脚本.sh 脱离终端jobs查看任务fg切前台bg切后台wait等待所有后台子进程全部执行完毕五、for 循环for 适合已知循环次数、遍历列表、遍历文件。两种语法。5.1 列表遍历语法for 变量 in 取值列表;do 命令 done5.2 C 语言风格语法数字循环for ((i1;i10;i));do 命令 done极简示例#!/bin/bash #列表方式 for i in {1..5};do echo $i done #C语言风格 for ((i1;i5;i));do echo $i done经典练习题 1九九乘法表#!/bin/bash for num1 in {1..9};do for ((num21;num2num1;num2));do echo -en $num2*$num1$[num2*num1]\t done echo done经典练习题 2水仙花数三位数每个位立方之和等于本身#!/bin/bash for num in {100..999};do n1$[num/100] n2$[num%100/10] n3$[num%10] if [ $[n1**3 n2**3 n3**3] -eq $num ];then echo $num fi done经典练习题 3百钱买百鸡公鸡 5 钱一只母鸡 3 钱一只小鸡 3 只 1 钱100 钱买 100 只鸡#!/bin/bash for ((cock1;cock20;cock));do for ((hen1;hen33;hen));do for chick in {3..100..3};do if [ $[cockhenchick] -eq 100 -a $[cock*5hen*3chick/3] -eq 100 ];then echo 公鸡:$cock 母鸡:$hen 小鸡:$chick fi done done done企业实战读取文件批量创建账号生成随机密码/tmp/users 存放用户名列表生成随机密码强制首次登录改密码#!/bin/bash users_info/etc/users users_list/tmp/users [ ! -f $users_info ] touch $users_info exec ${users_list} while read username;do pass$(echo x$RANDOM | md5sum | cut -c3-11) useradd $username /dev/null echo $pass | passwd --stdin $username /dev/null chage -d 0 $username echo username:$username password:$pass $users_info done小提示Shell 生成随机数常用方案$RANDOM0~32767openssl rand -base64 8date %s%N纳秒时间戳/dev/urandom、UUID六、select 交互式菜单循环select 专门用来做交互式选择菜单自动打印数字选项PS3修改提示符REPLY保存用户输入序号。语法select 变量 in 选项1 选项2 选项3;do 循环逻辑 done小提示select 不会自动退出代码内部需要手动写exit退出脚本。极简示例#!/bin/bash PS3请选择操作编号 select opt in 安装httpd 安装mysql 退出;do case $opt in 安装httpd) echo 开始安装httpd ;; 安装mysql) echo 开始安装mariadb ;; 退出) exit 0 ;; *) echo 输入无效请重新选择 esac done语法选型对比表表格语法适用场景if几乎所有条件判断通用支持字符串、数字、文件、正则case固定字符串匹配服务启停脚本菜单替代大量 elif函数封装重复代码脚本模块化复用代码片段while守护进程死循环按行读取文件不确定循环次数until条件不满足才循环生产很少使用可以用 while 替代for遍历列表、文件、已知数字循环次数批量操作主机、文件select快速生成交互式数字选择菜单⚠️【避坑总结】高频踩坑汇总[ ]括号内侧必须有空格❌错误[0 -eq 0]✅正确[ 0 -eq 0 ](( ))算术比较不需要空格只支持整数不能做字符串比较return只退出函数exit直接结束整个脚本不要搞混while 管道读取文件cat file | while read循环内部变量外部失效重定向done file写法规避子进程case 每个分支结尾不要忘记;;少写会穿透执行后面分支死循环while true必须加sleep否则 CPU 占满 100%函数先定义后调用写在调用代码的上方$?保存上一条命令返回值执行新命令$?值就被覆盖select 不会自动退出必须手动exitPS3修改菜单提示符REPLY拿到输入数字使用chattr i锁定文件修改前必须先执行chattr -i否则无法写入全文小结if 是万能条件case 擅长固定字符串匹配函数实现代码复用提高脚本可维护性。while 适合守护进程、读文件for 适合已知次数遍历until 可以被 while 替代select 快速做交互菜单。写运维脚本三步方法论需求分析 → 拆解设计思路 → 编码调试测试后上生产环境。写脚本优先在命令行把单条命令调试成功再粘贴到脚本中减少 bug。企业脚本服务监控、用户管理、批量账号、日志封禁 IP都是条件 循环组合出来。
阅读完成 · 觉得有帮助?