2026/10/24 5:23:46

【FDE系列】阶段2:Day 40:Shell 进阶 — 生产级脚本与本周收官

【FDE系列】阶段2:Day 40:Shell 进阶 — 生产级脚本与本周收官 前言FDE系列内容总纲【大纲】FDE 前沿部署工程师学习系列教程-CSDN博客前置课程列表见文档结尾附录。阶段2·Day 40Shell 进阶 — 生产级脚本与本周收官FDE 学习系列教程 · 第二阶段 · 第 4 周 · Day 5预计时长2.5 小时 | 难度★★★☆☆ | 前置知识Day 36-39 全部内容一句话目标掌握 set -euo pipefail 严格模式、trap 清理机制和 case 分支写出带 PID 管理的start/stop/status/restart服务脚本并完成本周总复习验收。‍‍ 开场你的脚本能跑和可靠是两回事昨天的备份脚本、健康检查脚本都能干活了。但 FDE 在客户现场写脚本光能跑不够还得出事不闯祸。先看两个真实翻车场景场景 1错误被无视脚本一路狂奔cd /data/important rm -rf * # 你以为在 /data/important 里其实上面 cd 失败了……如果cd因为目录不存在而失败默认情况下 Shell根本不会停会在当前目录继续执行rm -rf *——后果自己脑补。场景 2脚本中途被 CtrlC留下一地临时文件备份脚本正在打包到一半你按了 CtrlC临时文件残留在磁盘上跑十次攒十个垃圾。今天学三样东西给脚本装上安全气囊严格模式出错就停、trap退出时清理、case优雅的多分支。最后把它们组合成一个专业的服务管理脚本收官本周。 一、严格模式set -euo pipefail这一行你在 Day 38 的备份脚本里照抄过今天彻底搞懂它为什么是脚本护栏。#!/bin/bash set -euo pipefail三个开关一个一个拆set -e出错立刻停errexit#!/bin/bash # 不加 set -e 的默认行为 cd /一个不存在的目录 echo 我还是执行了 # cd 都失败了这行照样跑 # 加了 set -e set -e cd /一个不存在的目录 # 命令返回非0脚本立刻终止 echo 这行不会执行 # 不会走到这默认命令失败 → 打印一行错误 → 脚本厚着脸皮继续往下跑 → 后面的命令在错误的前提下执行可能闯大祸 set -e任何命令失败退出码非0→ 脚本立即停止 → 把事故扼杀在第一步 但有些命令失败是正常的比如grep没匹配到会返回 1。遇到这种需要临时放行的可以grep xxx || true——让整条语句的退出码永远是 0set -e 就不会停。set -u用了没定义的变量就报错nounset#!/bin/bash # 不加 set -u echo 要删除$DIRETORY # 手滑把 DIRECTORY 拼错成 DIRETORY rm -rf $DIRETORY/* # 变量不存在 → 变成空字符串 → rm -rf /* 方向发展…… # 加了 set -u set -u echo 要删除$DIRETORY # 脚本立刻报错DIRETORY: unbound variable变量未绑定终止这个开关专治变量名拼错和参数忘传——本来空字符串会悄悄制造灾难现在直接大声喊出来。配合默认值语法最稳SOURCE_DIR${1:-}即使参数没传变量也是显式定义的空值不会触发 set -u。set -o pipefail管道里任何一环失败都算失败# 默认情况下管道的退出码只看【最后一个】命令 false | echo hello # false 明明失败了但…… echo $? # 0因为最后一个 echo 成功了 # 加了 pipefail set -o pipefail false | echo hello echo $? # 非0管道中 false 的失败被如实传递实际场景# 没有 pipefail 时 cat 不存在的文件.log | grep ERROR # cat 报错了但 grep 成功执行没匹配到也算整体退出码可能是0 # → 你以为日志检查通过了其实文件根本没找到 # 有 pipefailcat 的失败会让整条管道失败问题藏不住三个开关总览┌──────────────────────────────────────────────────────────┐ │ set -e 命令失败立即退出默认继续 │ │ set -u 用未定义变量立即报错默认当空串 │ │ set -o pipefail 管道任一环节失败即失败默认只看末尾 │ └──────────────────────────────────────────────────────────┘ 经验法则 每个新脚本第二行#! 之后就写 set -euo pipefail 这是用无数事故换来的行业最佳实践严格模式小实验新建strict_test.sh分别注释/取消注释第一行开关对比输出#!/bin/bash set -euo pipefail echo 第 1 步开始 cd /tmp echo 第 2 步进入 /tmp 成功 cat /tmp/no_such_file_xyz | wc -l # pipefail 会让这里暴露 cat 失败 echo 第 3 步你不应该看到我如果上面失败 echo 使用未定义变量$NOT_DEFINED echo 第 4 步你也看不到我chmod x strict_test.sh ./strict_test.sh 二、trap脚本退出时的自动善后trap用来捕获信号——当脚本收到中断、或正常结束时自动执行一段清理动作。最常见的用途清理临时文件#!/bin/bash set -euo pipefail # ① 创建一个临时文件mktemp 生成系统保证不重名的临时路径 TEMP_FILE$(mktemp) echo 临时文件是$TEMP_FILE # ② 注册善后动作脚本【无论如何退出】时删除临时文件 trap echo → 触发清理删除 $TEMP_FILE; rm -f $TEMP_FILE EXIT # ③ 正常业务逻辑 echo 工作内容 $TEMP_FILE cat $TEMP_FILE echo 脚本即将结束…… # 即使这里正常走到头EXIT 陷阱也会触发临时文件被删mktemp是什么安全地创建一个唯一命名的临时文件返回其路径如/tmp/tmp.aB3xY9。关键优势避免重名冲突和竞态攻击。手写/tmp/myfile可能被别的进程/恶意程序抢占mktemp由系统保证唯一。默认在/tmp下创建权限为600仅当前用户可读写。$(...)命令替换把mktemp的输出临时文件路径赋值给变量TEMP_FILE。此后所有操作都基于这个路径避免硬编码。trap是什么trap用来捕获信号/事件在事件发生时执行指定命令。语法trap 要执行的命令 信号/事件EXIT事件EXIT不是普通信号而是脚本退出时这个事件——无论脚本是正常结束、exit N显式退出、因set -e遇错退出还是被信号终止部分信号EXIT陷阱都会触发。因此它常被用作finally 块收尾、清理、关连接、删临时文件。这条命令的含义触发时先打印→ 触发清理删除 $TEMP_FILE再执行rm -f $TEMP_FILE删除临时文件。rm -f强制删除文件不存在也不报错避免清理阶段再出错。运行后观察脚本结束时自动打印触发清理临时文件被删。为什么用单引号...单引号让$TEMP_FILE延迟到触发时才展开此时变量已有值。若用双引号$TEMP_FILE会在注册时就展开成当时的值——虽然这里值已确定但单引号是 trap 的推荐写法更稳妥、语义更清晰。⚠️ 这是易错点trap的命令用单引号能让变量在执行时再解析。测试按 CtrlC 试试把脚本改成带等待的版本#!/bin/bash set -euo pipefail TEMP_FILE$(mktemp) trap echo ; echo → 你按了 CtrlC但临时文件照样清理; rm -f $TEMP_FILE; exit 130 INT TERM echo 正在干活临时文件$TEMP_FILE echo 现在按 CtrlC 试试…… sleep 100 echo 正常结束 rm -f $TEMP_FILE./trap_test.sh # 运行中按 CtrlC # ^C # → 你按了 CtrlC但临时文件照样清理trap 捕获的常见信号┌──────────┬──────────────────────────────────────────┐ │ 信号 │ 触发时机 │ ├──────────┼──────────────────────────────────────────┤ │ EXIT │ 脚本【任何方式】结束时正常/出错/被杀 │ │ │ → 清理临时文件用它最省心兜底 │ │ INT │ 收到 CtrlCinterrupt │ │ TERM │ 被 kill默认信号要求终止时 │ │ HUP │ 终端挂断昨天讲的 SIGHUP │ └──────────┴──────────────────────────────────────────┘ 语法trap 要执行的命令 信号1 信号2 ... 多个信号用空格分隔 trap - 信号 可以取消已注册的陷阱 经验临时文件、锁文件、后台进程这三类脚本产生的副产品都应该用 trap 保证退出时清理。这样无论脚本怎么结束都不会在服务器上留垃圾。锁文件思路防止脚本重复运行了解cron 里的备份脚本可能上一次还没跑完、下一次又启动了。可以用锁文件防止重叠# 定义锁文件的路径。用 /tmp 下的文件作为标记文件存在 有实例在跑。 LOCK/tmp/backup.lock #注册退出时清理锁 trap rm -f $LOCK EXIT if [ -e $LOCK ]; then echo 上一次备份还在运行本次跳过 exit 0 fi touch $LOCK # ……正常备份逻辑……这是一段单实例锁single-instance lock的实现用来防止同一个脚本这里是备份脚本同时运行多份。检查锁是否存在-e $LOCK文件存在 → 说明上次还没释放锁 →本次直接跳过。exit 0以成功退出不是错误因为跳过是预期行为不该被 cron 当作失败告警。这块混个眼熟以后写长任务脚本时会想起来。 三、case优雅的多分支选择昨天健康检查脚本只有正常/异常两条路用 if 够了。但今天要写的服务管理脚本有四个动作start / stop / status / restart用一堆 if-elif 会很丑。case是 Shell 的switch专门处理多分支。基本结构case $变量 in 模式1) 匹配模式1时执行 ;; # ⚠️ 每个分支必须用 ;; 结尾两个分号 模式2) 匹配模式2时执行 ;; *) 以上都不匹配时兜底相当于 else ;; esac # case 倒着拼写结束小例子新建case_demo.sh#!/bin/bash set -euo pipefail ACTION${1:-help} case $ACTION in start) echo 启动中…… ;; stop) echo 停止中…… ;; restart) echo 重启中…… ;; status) echo 查询状态…… ;; help|*) echo 用法$0 {start|stop|status|restart|help} ;; esacchmod x case_demo.sh ./case_demo.sh start # 启动中…… ./case_demo.sh stop # 停止中…… ./case_demo.sh # 用法……没参数时走 help|* 兜底case 的模式匹配能力case $FILE in *.txt) echo 文本文件 ;; # 通配符匹配 .txt 结尾 *.py|*.sh) echo 代码/脚本文件 ;; # | 表示或 [0-9]*) echo 数字开头 ;; # 字符集 *) echo 其他类型 ;; esachelp|*)这个写法|表示或*匹配一切。把 help 和兜底分支合在一起——传 help 或传了乱七八糟的参数都显示用法说明。️ 四、综合实战服务管理脚本 service.sh把今天 昨天的东西全揉进去写一个像样的服务管理脚本。这是 FDE 部署项目的标配工具用 PID 文件管理进程支持 start/stop/status/restart。先理解 PID 文件的作用nohup 启动服务时把它的进程号写进一个文件app.pid │ ▼ stop 时读 app.pid 拿到 PID → 精确 kill 这个进程 status 时用 PID 查进程还在不在 重启时避免 pkill 误杀同名进程精准可控 app.pid 文件内容就一行数字9876新建service.sh放在~/fde_project旁边或里面路径按实际调整#!/bin/bash # # FDE API 服务管理脚本 # 用法./service.sh {start|stop|status|restart} # set -euo pipefail # ---------- 配置区按你的实际路径改---------- PROJECT_DIR/home/fde/fde_project VENV$PROJECT_DIR/venv UVICORN$VENV/bin/uvicorn APP_MODULEmain:app HOST0.0.0.0 PORT8000 HEALTH_URLhttp://localhost:${PORT}/health PID_FILE$PROJECT_DIR/app.pid LOG_FILE$PROJECT_DIR/app.log # ---------------------------------------------- # 日志函数 log() { echo [$(date %H:%M:%S)] $*; } # 读取 PID 文件判断进程是否存活 is_running() { [ -f $PID_FILE ] || return 1 local pid pid$(cat $PID_FILE) kill -0 $pid 2/dev/null # kill -0 不发真信号只探测进程在不在 } do_start() { if is_running; then log ⚠️ 服务已在运行PID$(cat $PID_FILE)无需重复启动 return 0 fi log 启动服务…… cd $PROJECT_DIR nohup $UVICORN $APP_MODULE --host $HOST --port $PORT \ $LOG_FILE 21 echo $! $PID_FILE # $! 是【刚启动的后台进程】的 PID # 等待健康检查通过最多等 ~15 秒 local i0 while [ $i -lt 15 ]; do if curl -sf $HEALTH_URL /dev/null 21; then log ✅ 服务已启动PID$(cat $PID_FILE)监听 $PORT return 0 fi i$((i1)) sleep 1 done log ❌ 启动后健康检查未通过请查看日志$LOG_FILE exit 1 } do_stop() { if ! is_running; then log ⚠️ 服务未运行 rm -f $PID_FILE return 0 fi local pid pid$(cat $PID_FILE) log 正在停止服务PID$pid…… kill $pid 2/dev/null || true # 优雅等待最多 10 秒 local i0 while [ $i -lt 10 ]; do kill -0 $pid 2/dev/null || break i$((i1)) sleep 1 done # 还没死就强杀 if kill -0 $pid 2/dev/null; then log ⚠️ 优雅停止超时强制结束 kill -9 $pid 2/dev/null || true fi rm -f $PID_FILE log ✅ 服务已停止 } do_status() { if is_running; then log ✅ 运行中PID$(cat $PID_FILE) curl -s $HEALTH_URL echo else log ❌ 未运行 return 1 fi } # ---------- 主入口用 case 分发命令 ---------- ACTION${1:-help} case $ACTION in start) do_start ;; stop) do_stop ;; status) do_status ;; restart) log 重启服务…… do_stop sleep 2 do_start ;; help|*) echo 用法$0 {start|stop|status|restart|help} echo start 启动服务并等待健康检查 echo stop 优雅停止超时强杀 echo status 查看运行状态 echo restart 重启 ;; esac完整使用流程chmod x service.sh # ① 启动带健康检查等待启动失败会明确报错 ./service.sh start # [15:00:01] 启动服务…… # [15:00:03] ✅ 服务已启动PID10234监听 8000 # ② 查状态 ./service.sh status # [15:00:10] ✅ 运行中PID10234 # {status:ok} # ③ 重复启动会被拦截 ./service.sh start # [15:00:15] ⚠️ 服务已在运行PID10234无需重复启动 # ④ 停止先礼后兵自动等 10 秒 ./service.sh stop # [15:00:20] 正在停止服务PID10234…… # [15:00:21] ✅ 服务已停止 # ⑤ 重启 ./service.sh restart # ⑥ 看看脚本为你管理的文件 ls -l ~/fde_project/app.pid # 运行时存在停止后自动删除 tail -20 ~/fde_project/app.log这个脚本专业在哪设计点体现的工程思想set -euo pipefail出错即停、变量防呆、管道真实成败PID 文件精准管理进程不误杀同名服务start 后等健康检查启动命令执行了 ≠ 服务真的能用了以健康检查为准stop 先 kill 等 10 秒再 kill -9给程序保存数据的机会优雅退出重复启动拦截防止起两个实例抢同一端口函数封装 do_start/do_stoprestart 能复用结构清晰配置区集中在顶部换项目只改配置不改逻辑服务生命周期一图流 ./service.sh start ./service.sh stop │ │ ▼ ▼ nohup 后台启动 killSIGTERM 礼貌劝退 PID 写入 app.pid 等待最多10秒 轮询 /health 等就绪 还活着→ kill -9 │ 删除 app.pid ▼ ┌─────────────────┐ │ 服务运行中 │ ← status 靠 PID /health 双重确认 │ 日志 → app.log │ └─────────────────┘ 这个service.sh的思路和企业里真正用的systemd service几乎一一对应PIDFile、ExecStart、ExecStop、Restartalways、健康探测。下周学 Docker、后续阶段接触 systemd/K8s 时你会发现概念全是通的——今天写的是手办版原理一模一样。 本周复习知识地图Linux 与 ShellDay 36-40 │ ├─ 文件操作Day 36 │ ├─ WSL2 Ubuntu 环境搭建 │ ├─ 文件系统/根、~家、/etc /var/log /tmp /mnt/c │ ├─ 路径绝对/相对. .. ~ - 四个特殊符号 │ ├─ 导航pwd / ls -lah / cd / find -name │ ├─ 增删mkdir -p / touch / cp -r / mv / rm -r⚠️ rm -rf / │ ├─ 查看cat / head / tail -f / less / wc -l │ └─ Linux差异正斜杠 /、大小写敏感、venv/bin/activate │ ├─ 权限·进程·文本Day 37 │ ├─ 权限位类型 u/g/o 三组 rwx │ ├─ 数字法 r4 w2 x1 → 755/644/600 │ ├─ chmod字母法/数字法、chown -R │ ├─ 进程ps aux、top/htop、kill/-9、killall、lsof -i:端口 │ ├─ 管道 | 与重定向 21 /dev/null │ └─ 三剑客grep过滤行/ awk取列统计/ sed替换 │ ├─ Shell 脚本Day 38 │ ├─ #!/bin/bash、echo、$(命令替换) │ ├─ 变量等号无空格$取值${} 边界 │ ├─ 参数 $0 $1 $# $、默认值 ${1:-x} │ ├─ 退出码 $?0成功、exit │ ├─ if [ ]括号有空格、-d/-f/-z、数字 -eq/-lt │ ├─ for / while、$(( )) 整数运算 │ ├─ 函数 f(){}、local、$1 传参 │ └─ 备份脚本tar -czf basename/dirname 日期命名 │ ├─ 无人值守Day 39 │ ├─ SIGHUP 信号原理 │ ├─ nohup 命令 log 21 │ ├─ screen -S / -r / CtrlA,D │ ├─ tail -f 实时日志 │ ├─ crontab 五颗星分时日月周、*/5 │ ├─ cron 三坑绝对路径、输出重定向、venv │ └─ 健康检查curl 探测 → 重试3次 → 自动重启 │ └─ 生产级脚本Day 40 ├─ set -e出错停/ -u未定义变量报错/ pipefail ├─ trap 清理 EXIT/INT/TERM、mktemp 临时文件 ├─ case 多分支;; 结尾* 兜底 ├─ PID 文件管理进程 └─ service.shstart/stop/status/restart 优雅停止 本周验收清单序号验收项达标标准自测1WSL 环境能在 Ubuntu 里自如操作whoami/pwd/uname正常2文件操作熟练用 15 命令Day36 练习 1 目录树搭出3路径概念分清绝对/相对路径和~ . ..能说出/home/fde/../fde是哪4权限看懂 rwx、会用 chmod/chown脚本能加 x 运行.env 设 6005排障 Permission denied能对症解决说得出三种病因和药方6进程会找 PID、会杀、会查端口启动→定位→kill uvicorn7三剑客grep/awk/sed 处理日志Day37 练习 3 全做对8管道重定向会用|组合、 21能统计日志 ERROR 条数9Shell 基础变量/参数/条件/循环/函数check_path.sh 跑通10备份脚本自动打包日期命名校验backup.sh 三参数都正常11后台运行nohup 关终端服务不死重开终端服务还在12screen会创建/脱离/恢复会话练习 2 全流程13crontab会配置定时任务分钟级任务验证后改回14健康检查挂了能自动重启kill 后脚本自动拉起15严格模式理解 set -euo pipefail能说清三个开关作用16服务脚本service.sh 四个动作start/stop/status/restart 全通过达标建议16 项里能独立完成 13 项以上本周就算扎实通过。有卡顿的项目回到对应那一天照着教程从头敲一遍——Linux 和 Shell 是手上功夫看懂不等于会写。 本周收官你获得了什么五天前你面对黑底白字的终端可能还发怵。现在你已经能你现在的 Linux 能力画像 ️ 环境 在 WSL2 Ubuntu 里安家Windows/Linux 自由切换 文件 不用鼠标命令行管理一切文件目录 权限 看懂 rwxPermission denied 不再求人 ⚙️ 进程 找得到、看得清、杀得掉、端口会排查 排障 grepawksedtail 在日志大海里捞针 脚本 把重复操作写成带校验和函数的自动化脚本 部署 nohup/screen 让服务常驻后台 ⏰ 调度 crontab 定时备份、定时巡检 自愈 健康检查 自动重启 ️ 健壮 严格模式、trap 清理、PID 管理把第 3 周的数据能力和本周的Linux 能力合起来看你已经走完了一条完整链路脏 CSV → pandas 清洗 → MySQL 存储 → FastAPI 提供服务 │ Linux 上后台常驻nohup/screen │ crontab 定时备份 健康检查自愈 日志排障这就是一台能在客户现场真正跑起来的小型应用服务器了。你现在干的活和初级运维/实施工程师的日常已经高度重合。 下周预告Docker / Nginx / GitLinux 手工部署你已经会了但它有个绕不开的痛点——换一台服务器所有环境得重装一遍Python 版本、依赖库、MySQL 客户端……配一次大半天还可能在我机器上能跑到你这就不行。下周用三大神器彻底解决Docker 容器化把应用依赖环境打包成一个盒子镜像到哪台机器docker run一下就跑环境完全一致Docker Compose一条命令同时拉起 API MySQL Nginx 整套环境Nginx 反向代理让用户通过标准 80 端口访问你的服务Git 版本控制代码有历史、能回滚、可协作不再靠文件夹改名备份本周你在 Linux 里手写的 nohup、crontab、健康检查下周会看到 Docker 如何用更优雅的方式把它们全部接管。周末好好歇下周进入现代部署的世界附录前置课程列表阶段一认知启蒙AI 认知与 FDE 角色AI 认知【FDE系列】阶段1Day 1AI 层级关系 — 四个嵌套的圈-CSDN博客【FDE系列】阶段1Day 2AI 三阶段发展史 — 会认 → 会判断 → 会创造-CSDN博客【FDE系列】阶段1Day 3符号 AI vs 机器学习 — 两条路线的本质区别-CSDN博客【FDE系列】阶段1Day 4Transformer 的历史意义 — 2017 年的分水岭-CSDN博客【FDE系列】阶段1Day 5本周复习与自测 — 检验你的 AI 认知地基-CSDN博客【FDE系列】阶段1Day 6Transformer 架构 — 一张图纸盖出千千万万栋楼-CSDN博客【FDE系列】阶段1Day 7LLM 本质 — 文字接龙机器-CSDN博客【FDE系列】阶段1Day 8Token — 模型眼中的最小单位-CSDN博客【FDE系列】阶段1Day 9AI 幻觉 — 为什么会一本正经地胡说八道-CSDN博客【FDE系列】阶段1Day 10上下文窗口 — 模型的记忆力上限 本周复习-CSDN博客【FDE系列】阶段1Day 11Prompt — 给模型立规矩-CSDN博客【FDE系列】阶段1Day 12Memory — 让模型记住上下文【FDE系列】阶段1Day 13RAG — 给模型配图书管理员-CSDN博客【FDE系列】阶段1Day 14Tool Use — 让模型动手操作-CSDN博客【FDE系列】阶段1Day 15MCP — 统一的工具接口标准 第三周复习-CSDN博客FDE 基础概念【FDE系列】阶段1Day 16什么是 FDE — 把 AI 变成客户结果的人-CSDN博客【FDE系列】阶段1Day 17FDE vs 传统实施 — 三大本质区别-CSDN博客【FDE系列】阶段1Day 18FDE 三重身份 C6 胜任力模型-CSDN博客【FDE系列】阶段1Day 19七阶段行动路径 行业经验的价值-CSDN博客【FDE系列】阶段1Day 20阶段总结与产出物 — 第一阶段收官-CSDN博客阶段二技术地基Python FastAPI SQL Docker API 集成Python基础【FDE系列】阶段2Day 21Python 环境搭建 — 写出你的第一行代码-CSDN博客【FDE系列】阶段2Day 22变量、数据类型、条件判断 — Python 的“记忆“和“判断“-CSDN博客【FDE系列】阶段2Day 23循环与函数 — 让代码跑 100 遍、把逻辑打包复用-CSDN博客【FDE系列】阶段2Day 24数据结构 — 列表、字典、集合、元组-CSDN博客【FDE系列】阶段2Day 25文件读写与 JSON — 让程序连通外部数据第一周收官-CSDN博客【FDE系列】阶段2Day 26模块化编程 — 把代码拆成“抽屉柜“-CSDN博客【FDE系列】阶段2Day 27异常处理与日志 — 让程序“摔不烂、查得到“-CSDN博客FastAPI入门到进阶【FDE系列】阶段2Day 28FastAPI 入门 — 把你的函数变成 API 服务-CSDN博客【FDE系列】阶段2Day 29FastAPI 进阶 — Pydantic 模型与完整 CRUD 实战-CSDN博客【FDE系列】阶段2Day 30生产代码规范 — 测试、类型注解、配置管理第二周收官-CSDN博客SQL基础【FDE系列】阶段2Day 31SQL 基础 — 增删改查一把梭-CSDN博客【FDE系列】阶段2Day 32多表查询 — JOIN 与聚合-CSDN博客【FDE系列】阶段2Day 33进阶查询 — 窗口函数与 CTE-CSDN博客【FDE系列】阶段2Day 34数据清洗 — 把脏数据捋干净-CSDN博客【FDE系列】阶段2Day 35Python SQL — 工单接入 MySQL 本周收官-CSDN博客【FDE系列】阶段2Day 36Linux 入门与文件操作 — 扔掉鼠标的第一天-CSDN博客【FDE系列】阶段2Day 37权限、进程与文本三剑客-CSDN博客【FDE系列】阶段2Day 38Shell 脚本 — 把命令串起来自动跑-CSDN博客【FDE系列】阶段2Day 39Linux 综合实战 — 让服务无人值守-CSDN博客