CodeRoad Map 程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。
由 程序员柏风 独立维护 · 关于作者
学习 更多
脚本语言
这一课你将能做到
用 Bash 脚本完成项目构建、日志清理、服务器健康检查的自动化
用 Python 编写调用云厂商 API 的工具脚本,处理 JSON/CSV 数据
能在 Java/Bash/Python 之间选对场景:什么时候用 Java 写业务,什么时候用脚本写运维
为什么要学
你已经学会了 Git 和 Linux,但每次部署还是手动敲命令?那说明你缺一门「胶水语言」——把各种工具串起来的能力。对 Java 后端来说,Bash 是服务器上的必备技能(因为服务器只有 shell),Python 是复杂运维任务的放大器(处理数据、调用 API、写工具)。
人话:Java 适合做「重活」(业务逻辑、高并发),但写个脚本删三天前的日志、拉阿里云 ECS 列表、批量处理 JSON,用 Java 就太重了。DevOps 讲究「选对工具做小事」,脚本语言就是专门用来写这类「小事」的,而且几分钟就能跑起来。
先建立图像
运维自动化的三层能力:
手动 SSH 敲命令 ← 已学(第 2 课)
│
▼ 把命令固化成文件
Bash 脚本(部署、检查、清理) ← 本课第一层
│
▼ 需要条件判断、循环、API 调用
Python 脚本(复杂逻辑、数据处理) ← 本课第二层
│
▼ 需要类型安全、长时间运行、高并发
Go 程序(基础设施级工具) ← 进阶时了解
代码量与运行时间对比:
任务 Bash Python Java
清理三天前的日志 3行 10行 50行+
部署脚本 30行 40行 200行+
调用阿里云 API 查资源 难 20行 80行+
跟着做
步骤 1:写第一个 Bash 部署脚本
把第 1 课的 deploy.sh 扩展为可用版本:
#!/bin/bash
set -euo pipefail # e=遇错退出 u=未定义变量报错 pipefail=管道失败传递
APP_NAME="myapp"
JAR_FILE="target/${APP_NAME}-0.0.1-SNAPSHOT.jar"
SERVER="appuser@1.2.3.4"
REMOTE_DIR="/opt/${APP_NAME}"
BACKUP_DIR="/opt/backups"
echo "=== 1. 本地构建 ==="
mvn clean package -DskipTests -q
if [[ ! -f "$JAR_FILE" ]]; then
echo "构建失败:找不到 $JAR_FILE" >&2
exit 1
fi
echo "=== 2. 备份旧版本 ==="
ssh "$SERVER" "mkdir -p ${BACKUP_DIR} && cp -v ${REMOTE_DIR}/app.jar ${BACKUP_DIR}/app-$(date +%Y%m%d%H%M).jar || true"
echo "=== 3. 上传新版本 ==="
scp "$JAR_FILE" "$SERVER:${REMOTE_DIR}/app.jar"
echo "=== 4. 远程重启并验证 ==="
ssh "$SERVER" << 'REMOTE'
sudo systemctl restart myapp
sleep 5
if curl -sf http://localhost:8080/actuator/health; then
echo "部署成功"
else
echo "健康检查失败,准备回滚" >&2
exit 1
fi
REMOTE
运行前记得:chmod +x deploy.sh,脚本里所有 "" 不要省,否则路径含空格会炸。
步骤 2:Bash 日志清理脚本
#!/bin/bash
# 清理 /var/log/myapp 下超过 7 天的日志,保留压缩文件
LOG_DIR="/var/log/myapp"
KEEP_DAYS=7
# find 的基本语法:在目录里找,条件 -mtime +天数 -type f,动作 -delete/-exec
echo "正在清理 ${KEEP_DAYS} 天前的日志..."
find "$LOG_DIR" -name "*.log" -type f -mtime +$KEEP_DAYS -print
delete_count=$(find "$LOG_DIR" -name "*.log" -type f -mtime +$KEEP_DAYS -delete | wc -l)
# 磁盘使用率大于 85% 时报警
usage=$(df -h "$LOG_DIR" | awk 'NR==2 {gsub(/%/,""); print $5}')
if [[ "$usage" -gt 85 ]]; then
echo "ALERT: 磁盘使用率 ${usage}%,请立即检查 ${LOG_DIR}" >&2
# 可以接 webhook 发到钉钉/飞书
fi
步骤 3:Python 调用阿里云 API 查 ECS 实例 #!/usr/bin/env python3
# pip install alibabacloud-ecs20140526
import json
from alibabacloud_ecs20140526 import Client
from alibabacloud_tea_openapi import models as open_api_models
def list_instances():
config = open_api_models.Config(
access_key_id='YOUR_KEY_ID', # 实际走环境变量:os.environ['ALICLOUD_ACCESS_KEY']
access_key_secret='YOUR_SECRET',
endpoint='ecs-cn-hangzhou.aliyuncs.com'
)
client = Client(config)
resp = client.describe_instances()
for inst in resp.body.instances.instance:
print(f"{inst.instance_id} | {inst.instance_name} | {inst.public_ip} | {inst.status}")
if __name__ == '__main__':
list_instances()
Python 的优势:有阿里云官方 SDK,几行代码就拿到数据;同样的功能用 Bash curl + jq 要三四十行还难调试。
步骤 4:Python 处理日志——找出 Spring Boot 报错次数最多的 TOP 10 #!/usr/bin/env python3
from collections import Counter
import re
logfile = 'application.log'
pattern = re.compile(r'ERROR .*? - (.*)')
errors = []
with open(logfile, 'r', encoding='utf-8') as f:
for line in f:
m = pattern.search(line)
if m:
# 提取异常类名,如 java.sql.SQLException
err = m.group(1).split(':')[0].strip()
errors.append(err)
for err, count in Counter(errors).most_common(10):
print(f"{count:4d} {err}")
Java 后端写这个要 50 行、编译、打包;Python 直接 python3 parse_log.py,改起来也快。
步骤 5:选择合适的语言 场景 推荐语言 理由 构建打包、SSH 部署、日志清理 Bash 服务器原生,不依赖额外环境 调用云 API、处理 JSON/CSV Python 库多,写起来快 高并发采集、长时间后台服务 Go 编译型,资源占用低 核心业务、并发处理、团队熟悉 Java 类型安全、生态成熟
讲清楚要点
Bash 脚本是必选项不是可选项 :你不可能在服务器上装个 JDK 只为了跑一个清理日志的程序。Bash 无处不在,但超过 100 行或需要复杂数据结构的脚本,请切 Python。
Python 是运维的瑞士军刀 :requests(HTTP)、boto3/alibabacloud(云 API)、pandas(数据处理)、ansible(配置管理)……运维场景几乎都有成熟的库。不需要精通,会用 Google 查 API 就行。
set -euo pipefail 是 Bash 的安全底座 :-e 遇到错误退出,-u 未定义变量报错,-o pipefail 让管道失败能传递。这三行让你少踩 80% 的坑。
脚本也要写注释和错误处理 :不要写成「能用就行的一次性脚本」,运维脚本生命周期很长,半年后你自己都看不懂。
密钥走环境变量,不要硬编码 :所有 YOUR_KEY_ID 都要替换为从环境变量读取,脚本里永远不要出现明文密码。
你可能会懵的地方
Python 2 还是 Python 3?
必须用 Python 3。Python 2 已于 2020 年停止维护,所有主流 Linux 发行版的默认 python3 都是 3.8+。脚本首行写 #!/usr/bin/env python3 保险。
Bash 里 "" 和 '' 有什么区别?
"" 内的变量会被展开(echo "$HOME" → /root),'' 内纯文本原样保留。文件名和路径变量永远加 "",防止空格炸。
脚本路径要不要写绝对路径?
在脚本里调用其他命令时,尽量用绝对路径(/usr/bin/java 而非 java),因为 cron 或 systemd 启动的环境 PATH 可能不一样。或者脚本开头显式 export PATH=/usr/local/bin:$PATH。
$? 是什么?
上一条命令的退出码。0 表示成功,非 0 表示失败。if mycmd; then ... fi 就是判断 $? 是否为 0。养成「脚本每一大步都检查是否成功」的习惯。
cron 定时任务怎么写?
crontab -e 编辑,格式:分 时 日 月 星期 命令。例如每天 3 点清理日志:0 3 * * * /opt/scripts/cleanup.sh >> /var/log/cleanup.log 2>&1。注意 cron 环境变量很少,脚本里 PATH 要写全。
错法对照 错法 问题 正解 Bash 不写 set -e 某条命令失败,脚本继续跑,掩盖问题 set -euo pipefail 放第二行变量不加引号 rm -rf $dir dir 为空时变成 rm -rf / "$dir"密钥硬编码在脚本里 泄露风险,历史记录永久存在 export ALICLOUD_KEY=xxx 后脚本读环境变量Python 脚本没有 shebang 直接执行报错 第一行 #!/usr/bin/env python3 Bash 脚本超过 200 行还在硬撑 难维护、难调试、数组弱 切 Python
卡点急救
Bash 脚本里中文乱码 :脚本保存为 UTF-8,文件头加 export LANG=zh_CN.UTF-8,传输时用 scp -O 或 rsync 保证编码。
Python 模块找不到 :pip install xxx 装到了用户目录,但脚本用 root 跑的,路径不同。统一用虚拟环境(python3 -m venv venv),或在系统级安装 pip install --system。
脚本在终端能跑,放到 cron 里不行 :99% 是 PATH 或工作目录不对。cron 里写绝对路径,或在脚本开头显式 cd /opt/app && export PATH=...。
面试常问
Bash 里 $* 和 $@ 的区别?
"$*" 把所有参数拼成一个字符串,"$@" 保持每个参数独立。传给其他命令时用 "$@": mycmd "$@"。
怎么让脚本后台长期运行?
简单场景用 nohup ./script.sh &,但更好的做法是用 systemd 管(像第 2 课管 Java 一样),支持自动重启、日志收集、开机自启。
Python 做运维有什么优缺点?
优点:库生态极丰富,写起来快,可读性好;缺点:需要运行时环境(服务器要有 Python),纯计算性能不如 Go/Java。对运维任务来说,开发速度远比运行时性能重要。
自测三问
set -euo pipefail 每一部分的作用是什么?缺了 -u 会有什么隐患?
写一条 Bash 命令:找出 /var/log 下大于 100MB 的文件,按大小排序显示前 10 个。
你有一台新服务器需要装 JDK、Nginx、Docker,你会选 Bash 还是 Python 写初始化脚本?为什么?
小结一句话 脚本语言是 DevOps 的效率杠杆:Bash 解决服务器上的「顺手自动化」,Python 解决需要逻辑和数据处理的「复杂自动化」。
延伸