Linux 基础与 Shell 脚本:从文件系统到自动化部署
说实话,很多刚入行的运维同学觉得 Linux 就是敲命令,没什么技术含量。但我在云原生环境里摸爬滚打这些年,发现恰恰是这些基础功底,决定了你排查问题的速度。今天咱们就把 Linux 文件系统、三剑客命令、Vim 和自动化脚本串起来,讲点真正能用在生产环境的东西。
Linux 文件系统:你得知道文件放哪儿
Linux 的文件系统是树形结构,从根目录 / 开始。我见过不少事故,都是因为不清楚各个目录的用途,乱放文件导致的。
| 目录 | 用途 | 避坑点 |
|---|---|---|
/etc |
系统配置文件 | 别乱改,改前备份 |
/var |
日志、缓存、数据库 | 监控磁盘空间,容易写满 |
/tmp |
临时文件 | 重启会清空,别放重要数据 |
/usr/local |
用户安装的软件 | 编译安装放这里,别污染系统 |
/opt |
第三方软件 | 我习惯把中间件放这儿 |
我曾经遇到过一台服务器因为
/var/log 日志写满,导致数据库直接 crash。从那以后,我养成了两个习惯:一是给 /var 单独分区,二是用 logrotate 做日志轮转。
三剑客:grep、awk、sed
这三个命令,说白了就是文本处理的瑞士军刀。你想想看,生产环境里几万行日志,总不能一行行翻吧?
grep:搜索过滤
最常用的就是 grep -E 扩展正则。我个人习惯用 grep -n 显示行号,方便定位。
# 查找 ERROR 日志,忽略大小写,显示行号
grep -in "error" /var/log/app.log
# 递归搜索目录下所有文件
grep -r "timeout" /etc/nginx/
# 显示匹配行的前后各 5 行上下文
grep -C 5 "OutOfMemory" /var/log/app.log
小技巧:用
grep -v 排除干扰行。比如查异常日志时,先排除掉健康检查的日志,能省不少时间。
awk:列处理与格式化
awk 默认按空格或制表符分割列。我在项目中经常用它来提取日志中的关键字段。
# 打印第 1 列和第 3 列
awk '{print $1, $3}' access.log
# 以冒号为分隔符,打印第 1 列
awk -F':' '{print $1}' /etc/passwd
# 统计每个 IP 的访问次数
awk '{count[$1]++} END {for (ip in count) print ip, count[ip]}' access.log
嗯,这里要注意:awk 的 END 块是在所有行处理完后执行的,适合做汇总统计。
sed:流式编辑
sed 适合批量替换和删除。我经常用它来修改配置文件,比手动编辑快多了。
# 替换文件中的字符串(原地修改)
sed -i 's/old_host/new_host/g' /etc/nginx/nginx.conf
# 删除空行
sed -i '/^$/d' config.txt
# 在第 10 行后插入一行
sed -i '10a\new_line' file.txt
避坑指南:用
sed -i 前,一定要先不加 -i 跑一遍看看输出对不对。我曾经手滑把线上配置改坏了,还好有备份。
Vim 编辑器:别只会 i 和 Esc
Vim 的学习曲线确实陡,但一旦上手,效率翻倍。我建议你至少掌握这几个模式:
- 普通模式:按
dd删除行,yy复制行,p粘贴 - 插入模式:按
i在光标前插入,o在下一行插入 - 可视模式:按
v选中文本,然后批量操作 - 命令模式:按
:进入,输入wq保存退出,q!强制退出
# 常用命令速查
:set nu # 显示行号
:%s/old/new/g # 全局替换
:!command # 执行外部命令,比如 :!ls
我个人习惯把
set nu 和 set ts=4 写进 ~/.vimrc,这样每次打开 Vim 都自动显示行号,缩进也统一。
编写第一个自动化部署脚本
好了,前面都是铺垫。现在咱们写一个真正的自动化部署脚本。这个脚本我在多个项目里都用过,核心逻辑就是:拉代码、编译、备份、部署、重启。
#!/bin/bash
# 自动化部署脚本 - deploy.sh
# 用法: ./deploy.sh [service_name]
set -e # 遇到错误立即退出
set -u # 使用未定义变量时报错
# 配置区
APP_NAME="${1:-myapp}"
DEPLOY_DIR="/opt/${APP_NAME}"
BACKUP_DIR="/backup/${APP_NAME}"
GIT_REPO="git@github.com:company/${APP_NAME}.git"
BRANCH="main"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 1. 拉取最新代码
log "拉取代码..."
cd /tmp
if [ -d "${APP_NAME}" ]; then
cd "${APP_NAME}"
git pull origin "${BRANCH}"
else
git clone -b "${BRANCH}" "${GIT_REPO}"
cd "${APP_NAME}"
fi
# 2. 编译(以 Java 项目为例)
log "开始编译..."
mvn clean package -DskipTests
# 3. 备份旧版本
log "备份旧版本..."
if [ -d "${DEPLOY_DIR}" ]; then
backup_name="${APP_NAME}_$(date '+%Y%m%d_%H%M%S').tar.gz"
tar -czf "${BACKUP_DIR}/${backup_name}" -C "${DEPLOY_DIR}" .
log "备份完成: ${backup_name}"
fi
# 4. 部署新版本
log "部署新版本..."
cp target/*.jar "${DEPLOY_DIR}/app.jar"
# 5. 重启服务
log "重启服务..."
systemctl restart "${APP_NAME}"
# 6. 健康检查
sleep 5
if curl -sf http://localhost:8080/health; then
log "部署成功!"
else
log "健康检查失败,请手动排查"
exit 1
fi
我曾经在脚本里忘了加
set -e,结果编译失败后脚本继续往下跑,把旧版本也覆盖了。那一次线上故障让我记住了:脚本开头一定要加错误处理。
本章知识体系
下面这张图把今天的内容串起来了。你想想看,从文件系统到命令,再到脚本,其实是一条完整的链路。
说白了,今天讲的这些东西,最终都指向一个目标:让重复的工作自动化。文件系统是基础,三剑客是工具,Vim 是编辑器,脚本是最终产出。你把这些串起来,就能写出真正能上生产环境的部署脚本。