news 2026/10/14 18:26:55

shell 脚本知识点总结

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
shell 脚本知识点总结

Shell 脚本知识点总结

适用:Linux bash,运维面试、写自动化脚本、日志处理、批量操作

一、基础概念

  1. 脚本开头
#!/bin/bash # 告诉系统用bash解释执行,必须写在第一行 # 注释:# 单行注释;没有原生多行注释,可使用 :<<EOF ... EOF 模拟多行注释
  1. 执行方式
# 方式1(推荐,新开子shell) bash test.sh sh test.sh # 方式2(需要执行权限) chmod +x test.sh ./test.sh # 方式3(当前shell执行,不新建子shell,变量会留在当前环境) source test.sh . test.sh

重点:source在当前 shell 运行;./xxx.sh开启子 shell,脚本内变量执行完自动销毁。

二、变量

1. 普通变量

name="zhangsan" # =两边**不能有空格** echo $name echo ${name} # 推荐大括号,变量和后面字符区分开
  • 字符串有空格必须加引号:msg="hello world"
  • 单引号' ':原样输出,不解析变量;双引号" ":解析变量、转义字符

2. 特殊位置变量(脚本传参)

表格

变量含义
$0脚本本身名称
$1 $2 ... $n第 1、2、n 个参数
$#传入参数总个数
$*所有参数,当成1 个字符串(被双引号包裹时)
$@所有参数,独立多个字符串(循环推荐用 $@)
$?上一条命令返回值,0 = 成功,非 0 = 失败
$$当前脚本 PID
$!后台运行的最后一个进程 PID

面试高频:$*和$@区别,双引号下差异最大。

3. 只读变量 & 删除变量

readonly age=20 # 只读,不能修改 unset name # 删除变量,不能删只读变量

三、运算符

1. 算术运算(bash 只支持整数)

# 写法1 $(( )) 【最推荐】 a=$((1+2)) b=$((a*3)) # 写法2 expr 注意运算符两边空格 c=`expr 1 + 2`

⚠️ bash不支持小数运算,小数要用bc工具:

echo "scale=2; 10/3" | bc

2. 比较运算符([ ]测试,两边必须空格)

数字比较

表格

符号含义
-eq等于 equal
-ne不等于 not equal
-gt大于 greater than
-lt小于 less than
-ge大于等于
-le小于等于
if [ $a -gt 10 ];then echo ">10";fi
字符串比较

表格

符号含义
=相等
!=不等
-z str字符串长度为 0(空)
-n str字符串非空
[ "$name" = "root" ]

字符串变量建议双引号包裹,防止变量为空时报语法错误。

文件测试(高频!运维脚本)

表格

参数作用
-f是否存在且是普通文件
-d是否存在且是目录
-e文件 / 目录是否存在
-r可读
-w可写
-x可执行
-s文件存在且大小 > 0(非空文件)
if [ -f "/etc/passwd" ];then echo "文件存在";fi

3. 逻辑运算符

[ 条件1 ] && [ 条件2 ] # 与 [ 条件1 ] || [ 条件2 ] # 或 ! [ 条件 ] # 非

双中括号[[ ]]是 bash 扩展,支持 && ||,不用分开写,更稳定:

[[ $a -gt 5 && $a -lt 10 ]]

四、流程控制

1. if 判断

if [ 条件 ];then 命令 elif [ 条件 ];then 命令 else 命令 fi

2. case 分支(匹配字符串)

case $var in "start") echo "启动服务" ;; "stop") echo "停止服务" ;; *) echo "未知参数" ;; esac

3. for 循环

# 方式1 遍历列表 for i in $@ do echo $i done # 方式2 C风格for(bash) for ((i=0;i<10;i++)) do echo $i done

4. while 循环

# 读取文件经典写法 while read line do echo $line done < test.txt # 数字循环 i=1 while [ $i -le 5 ] do echo $i i=$((i+1)) done

until:条件不成立时循环,很少用。

五、函数

# 定义,必须先定义再调用 func(){ echo "函数" echo $1 # 函数内部参数,独立于脚本参数 return 0 # 返回值只能0~255整数 } func hello # 调用,传参 echo $? # 获取函数return返回值

函数返回值只能是状态码;想要返回字符串,用 echo 输出,变量捕获:

res=$(func)

六、字符串处理

str="abcdef" # 获取长度 ${#str} # 切片:${变量:起始位置:长度},下标从0开始 ${str:1:3} # bcd # 替换 ${str/a/x} # 替换第一个a为x ${str//a/x} # 替换全部a为x # 删除 ${str#ab} # 从开头最短删除ab ${str%ef} # 从结尾最短删除ef

七、数组

# 一维数组 arr=("apple" "banana" "orange") echo ${arr[0]} # 取第0个元素 echo ${arr[@]} # 全部元素 echo ${#arr[@]} # 数组长度 arr[2]="grape" # 修改元素

bash 只有一维数组,不支持二维数组。

八、输入输出

  1. read 接收控制台输入
read -p "请输入名字:" name read -s passwd # -s 不回显(密码) read -t 5 var # 5秒超时
  1. 重定向
> 覆盖输出 >> 追加输出 < 输入重定向 2> 错误输出重定向 &> 标准输出+错误输出全部重定向
  1. 管道|:前命令 stdout 作为后命令 stdin
ps aux | grep nginx

九、常用内置命令 & 工具

  • seq:生成序列seq 1 10
  • cut:截取列,cut -d: -f1 /etc/passwd
  • awk:文本分析(shell 脚本三剑客最强)
  • sed:流编辑,替换文本sed 's/old/new/g' file
  • grep:过滤文本

三剑客:grep (过滤) → sed (增删改) → awk (统计、格式化输出)

十、脚本调试

# 逐行打印执行过程,调试 bash -x test.sh # 只检查语法不执行 bash -n test.sh # 脚本内开启调试 set -x # 开启 set +x # 关闭

十一、常见坑(面试重点)

  1. =赋值两边不能有空格
  2. [ ]条件前后必须留空格
  3. 变量引用尽量"$var"双引号,防止空格、空值炸脚本
  4. $?只能保存上一条命令状态,中间不能插入其他命令
  5. bash 算术只支持整数,小数计算用 bc
  6. $*和$@在双引号下行为不一样
  7. 子 shell 内修改变量,不会影响父 shell(管道会创建子 shell)
  8. 函数 return 只能返回 0~255,不能返回字符串

十二、面试简答速记版

  1. shell 脚本开头#!/bin/bash
  2. 执行方式:./需要权限;source在当前 shell 执行
  3. $1 $# $? $@位置参数含义
  4. 数字比较-eq/-gt,不能直接用><(>在 [] 里是重定向)
  5. 文件判断-f -d -e
  6. [[ ]]比[ ]更强大,支持 && || 正则
  7. for、while 循环,读取文件 while read 经典写法
  8. 函数定义、传参、return 限制
  9. bash -x 调试脚本
  10. 三剑客:grep sed awk

===================================

常见shell脚本

1.mysql备份脚本

我写过生产环境的 MySQL 定时备份脚本,用 mysqldump 配合 gzip 压缩,crontab 每天凌晨执行,find -mtime 清理7天前的旧备份。上线时踩过 cron 环境变量导致 mysqldump 找不到的坑,改成绝对路径

#!/bin/bash DATE=$(date +%Y%m%d_%H%M%S) DB_USER="root" DB_PASS="123456" DB_NAME="testdb" BACKUP_DIR="/data/backup" # 备份并压缩 mysqldump -u${DB_USER} -p${DB_PASS} ${DB_NAME} | gzip >${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz # 删除7天前的旧备份 find ${BACKUP_DIR} -name "*.sql.gz" -mtime +7 -exec rm -f {} \;

2.服务器主机状态监控脚本

编写 Shell 脚本定时采集 CPU、内存、磁盘使用率和服务进程状态,超过阈值时记录日志并发送告警;结合crontab实现无人值守运行,减少人工巡检次数。

#!/bin/bash CPU_THRESHOLD=0.1 MEM_THRESHOLD=2 DISK_THRESHOLD=2 LOG="/var/log/monitor.log" # 每次执行先清空旧日志,防止重复发送历史告警 > ${LOG} # 获取cpu使用率 CPU_USAGE=$(top -b -n2 | grep Cpu | awk '{print 100 - $8}' | tail -n1) # 获取内存使用率 MEM_USAGE=$(free | awk '/Mem/{printf("%.0f", ($2-$7)/$2*100)}') # 获取根分区磁盘使用率 DISK_USAGE=$(df -h / | awk 'NR==2{print $5}' | cut -d'%' -f1) # 触发告警时,同时echo打印 + 写入日志 if (( $(echo "$CPU_USAGE > $CPU_THRESHOLD" | bc -l) ));then MSG="CPU告警:当前使用率${CPU_USAGE}%" echo "${MSG}" echo "${MSG}" >> ${LOG} fi if (( $(echo "$MEM_USAGE > $MEM_THRESHOLD" | bc -l) ));then MSG="内存告警:当前使用率${MEM_USAGE}%" echo "${MSG}" echo "${MSG}" >> ${LOG} fi if (( $(echo "$DISK_USAGE > $DISK_THRESHOLD" | bc -l) ));then MSG="磁盘告警:当前使用率${DISK_USAGE}%" echo "${MSG}" echo "${MSG}" >> ${LOG} fi # ===================== 钉钉机器人推送部分 ===================== # [ -s ${LOG} ] 判断:文件存在并且文件大小>0(里面有告警内容) if [ -s ${LOG} ];then curl -s -X POST "https://oapi.dingtalk.com/robot/send?access_token=fc9cf6ed0fa6a27d94d3fdbe65b648d89d933ed9c143f8fa6c87767bfc2aba3e" \ -H 'Content-Type: application/json' \ -d "{ \"msgtype\":\"text\", \"text\":{ \"content\":\"服务器资源告警:\n$(cat ${LOG})\" } }" fi

3.Nginx 访问日志分析脚本

使用awk、sort、uniq等命令统计访问日志中的 Top IP、状态码分布和异常请求,辅助快速定位访问异常。

#!/bin/bash # Nginx 访问日志分析脚本 LOG_FILE="${1:-/var/log/nginx/access.log}" [ -f "$LOG_FILE" ] || { echo "错误:日志文件不存在 $LOG_FILE" >&2; exit 1; } [ -s "$LOG_FILE" ] || { echo "日志为空,无数据可分析"; exit 0; } # 空文件防御 echo "==========================================" echo "Nginx 访问日志分析报告 $(date '+%F %T')" echo "日志文件:$LOG_FILE" echo "==========================================" echo -e "\n【1】PV/UV" printf "PV: %s UV: %s\n" "$(wc -l < "$LOG_FILE")" \ "$(awk '{print $1}' "$LOG_FILE" | sort -u | wc -l)" echo -e "\n【2】总流量" awk '{sum+=$10} END{printf "%.2f MB\n", sum/1024/1024}' "$LOG_FILE" echo -e "\n【3】访问 Top10 IP" awk '{c[$1]++} END{for(i in c) print c[i], i}' "$LOG_FILE" | sort -rn | head -10 echo -e "\n【4】状态码分布" awk '{c[$9]++} END{for(i in c) print c[i], i}' "$LOG_FILE" | sort -rn echo -e "\n【5】异常请求(4xx/5xx)分布" awk '$9 ~ /^[45]/ {c[$9]++} END{for(i in c) print c[i], i}' "$LOG_FILE" | sort -rn echo -e "\n【6】404 来源 Top5(疑似扫描)" awk '$9==404 {c[$1]++} END{for(i in c) print c[i], i}' "$LOG_FILE" | sort -rn | head -5 echo -e "\n【7】热门 URL Top10" awk '{c[$7]++} END{for(i in c) print c[i], i}' "$LOG_FILE" | sort -rn | head -10 echo -e "\n【8】每小时请求分布" awk '{h=substr($4,14,2); c[h]++} END{for(i in c) print i":00", c[i]}' "$LOG_FILE" | sort -n echo -e "\n【9】User-Agent Top5" awk -F'"' '{c[$6]++} END{for(i in c) print c[i], i}' "$LOG_FILE" | sort -rn | head -5
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 18:25:52

MySQL JSON_EXTRACT完全指南:路径语法、索引优化与实战场景

1. 项目概述与使用动机1.1 为什么偏偏是 JSON_EXTRACT我最初接触到JSON_EXTRACT这个函数&#xff0c;是在处理一张业务埋点表的时候。当时的需求说起来也不复杂&#xff0c;运营同事想要从一列名为extra_info的 JSON 字符串里&#xff0c;把用户的下单渠道、广告来源、页面停留…

作者头像 李华
网站建设 2026/10/14 18:25:15

ponytail插件与skill完全指南:从安装配置到高效任务编排

1. 从“ponytail”这个标题说起&#xff1a;它到底是什么第一次看到“ponytail”这个词&#xff0c;很多人脑子里蹦出来的画面是扎起来的马尾辫。但在技术圈和工具圈里&#xff0c;ponytail 早就不是发型那么简单了。最近一段时间&#xff0c;ponytail skill、ponytail 插件、插…

作者头像 李华
网站建设 2026/10/14 18:24:23

PySide2 QMenuBar与QMenu实战:从菜单栏到右键菜单

QMenuBar和QMenu这两个类&#xff0c;做过GUI开发的人应该都不陌生&#xff0c;但说实话&#xff0c;很多新手写PySide2界面时最容易忽略的就是菜单栏。界面拖几个控件、绑几个信号&#xff0c;觉得功能差不多了&#xff0c;菜单能省就省。可真到了交付项目的时候才发现&#x…

作者头像 李华
网站建设 2026/10/14 18:24:21

Qt 2D绘图示例全解析:从QPainter基础到工程实践

在Qt圈子里&#xff0c;说起入门绘图&#xff0c;多少人第一个跑起来的程序就是自带的2D Painting示例。这个例子藏在Qt安装目录的Examples里&#xff0c;平时容易被忽略&#xff0c;但真要说把QPainter那套东西讲明白&#xff0c;它比市面上大半教程都靠谱。我用这个示例拆过不…

作者头像 李华
网站建设 2026/10/14 18:23:27

降重降AI两不误!2026这3款降AIGC软件太绝了!

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 18:22:57

权游人物关系图谱:用图模型与模拟器解码维斯特洛

打开本地项目文件夹&#xff0c;几十个以日期和数字命名的存档里&#xff0c;“A Game of Thrones(83)” 格外显眼。别误会&#xff0c;这不是剧集第83集&#xff0c;也不是原著第83章&#xff0c;而是我为了弄懂这部作品里盘根错节的人物关系&#xff0c;迭代到第83版的数据项…

作者头像 李华