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,结果编译失败后脚本继续往下跑,把旧版本也覆盖了。那一次线上故障让我记住了:脚本开头一定要加错误处理。

本章知识体系

下面这张图把今天的内容串起来了。你想想看,从文件系统到命令,再到脚本,其实是一条完整的链路。

Linux 基础与 Shell 脚本知识体系 Linux 基础与 Shell 脚本知识体系 Linux 基础 文件系统 三剑客命令 Vim 编辑器 /etc /var /usr/local grep awk sed 普通模式 插入模式 命令模式 自动化部署脚本 核心:拉代码 → 编译 → 部署

说白了,今天讲的这些东西,最终都指向一个目标:让重复的工作自动化。文件系统是基础,三剑客是工具,Vim 是编辑器,脚本是最终产出。你把这些串起来,就能写出真正能上生产环境的部署脚本。