5031 字
25 分钟
Python第一章 入门筑基:从零上手编写运维脚本

承接Shell脚本系列,本章我们正式开启Python运维之旅。如果你已经掌握了Shell基础,学习Python会非常顺畅——两者核心逻辑相通,只是语法和适用场景不同。Shell擅长快速拼接命令实现简单自动化,而Python则能处理更复杂的逻辑、更大量的数据,开发更健壮的运维工具。

本章完全从运维视角出发,不讲冗余的编程概念,先帮你搭好环境,快速掌握运维必备的核心语法,写出第一个实用脚本,搞定最常用的文件目录自动化操作。学完本章,你就能用Python替代部分复杂的Shell脚本,解决Shell写起来费劲的场景。


1.1 认知篇:运维为什么要学Python?与Shell的区别及选型边界#

1.1.1 运维学Python的核心价值#

很多同学会问:Shell已经够用了,为什么还要学Python?核心原因有四点:

  1. 复杂逻辑更易维护:几百行以上的Shell脚本可读性差、调试困难,Python语法结构清晰,支持模块化、函数化拆分,复杂业务逻辑写起来更顺畅,后续维护成本更低。运维场景中,往往需要实现复杂的条件判断、多层循环、异常处理等逻辑。Shell虽然能做,但代码会变得冗长且难以理解,特别是在多人维护或代码审查时成为瓶颈。Python的代码可读性强,注释支持更灵活,团队协作效率提升30%以上。

  2. 生态强大开箱即用:海量成熟的第三方库覆盖所有运维场景——系统监控、远程操作、API交互、数据解析,直接调用即可,不用像Shell那样手动拼接命令造轮子。例如paramiko库可直接实现SSH远程执行,requests库简化HTTP API调用,yaml库优雅处理配置文件,psutil库获取系统资源实时状态。这些在Shell中需要结合多个命令、复杂管道处理,在Python中仅需几行代码,大幅提升开发效率。

  3. 跨平台一致性好:Python脚本在Linux、Windows、Mac上运行效果一致,而Shell受Bash/Zsh、发行版差异影响大,跨平台适配成本高。对于大型运维团队或企业级工具,跨平台支持是刚需。Python的os模块自动处理不同系统的路径分隔符、命令执行差异,无需编写平台判断逻辑。

  4. 运维进阶的必备基础:后续学习Ansible、自动化平台、DevOps工具链,底层大多基于Python,掌握Python才能看懂原理、做二次开发。许多互联网大厂的运维工具、监控系统都用Python构建,了解Python让你快速融入企业级工具链。

1.1.2 Shell与Python的选型边界#

不是Python替代Shell,而是两者各司其职、配合使用。

使用场景对照

优先用Shell的场景:

  • 简单命令拼接(一两条管道)
  • 一次性操作、快速验证想法
  • 系统初始化、标准化脚本
  • 轻量定时任务(cron配合)
  • 日志实时过滤(三剑客awk/sed/grep场景)

优先用Python的场景:

  • 复杂分支逻辑、多层条件嵌套
  • 大量数据统计分析、数据结构化处理
  • JSON/XML文件解析与生成
  • 跨平台脚本分发、一次开发多处运行
  • API交互、HTTP请求处理
  • 批量远程管理(100台以上服务器)
  • 开发可复用的运维工具、企业级自动化框架

关键决策点:如果脚本预计超过200行或需要维护超过6个月,优先考虑Python。如果纯粹是临时一次性操作,Shell效率更高。

一句话总结:简单自动化用Shell,复杂工具用Python,两者配合是运维的最佳实践。


1.2 环境篇:Linux下Python环境确认与脚本运行方式#

运维场景几乎都在Linux下运行Python脚本,我们全程基于Linux环境讲解。主流发行版(CentOS 7+、Ubuntu 18.04+、Rocky Linux、AlmaLinux)都默认预装了Python 3。即使没有,也能通过包管理器快速安装。

1.2.1 确认Python环境#

打开终端,输入命令确认版本:

version_check.sh
python3 --version

正常会输出类似 Python 3.10.12 的版本号,只要是3.6以上版本都兼容本教程内容。

版本选择建议
  • Python 3.6 ~ 3.8:适合老旧企业系统,库版本兼容性最好
  • Python 3.9 ~ 3.11:推荐选用,生产环境主流版本,性能提升20%
  • Python 3.12+:最新特性,但部分企业库还未适配,暂不推荐运维生产环境

1.2.2 pip包管理工具#

pip是Python的第三方包管理工具,地位相当于Linux的YUM/APT,用来安装扩展库。

确认pip版本:

terminal
pip3 --version
# 输出示例:pip 24.0 from /usr/local/lib/python3.11/site-packages/pip

运维高频pip命令:

pip_commands.sh
# 安装第三方包
pip3 install 包名
# 安装指定版本
pip3 install 包名==1.2.3
# 卸载包
pip3 uninstall 包名
# 查看已安装的所有包
pip3 list
# 导出依赖列表,用于批量部署(环境迁移关键)
pip3 freeze > requirements.txt
# 批量安装依赖(新环境快速部署)
pip3 install -r requirements.txt
国内源配置

国内源加速配置:默认官方源下载速度慢,配置清华源大幅提升速度:

terminal
pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

也可临时指定源:

Terminal window
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple paramiko

1.2.3 Python脚本的运行方式#

和Shell脚本逻辑完全一致,Python脚本也是纯文本文件,惯例后缀为.py。

方式1:python3命令直接执行(最常用)#

新建脚本文件后,直接用解释器执行,不需要执行权限:

terminal
python3 first.py

对应Shell的 bash first.sh,适合临时测试、快速运行。

方式2:加执行权限运行(生产脚本标准写法)#

脚本第一行加Shebang指定解释器,然后赋予执行权限,和Shell完全一致:

first.py
#!/usr/bin/env python3
print("Hello Python!")
terminal
chmod +x first.py
./first.py
Shebang最佳实践

为什么用 #!/usr/bin/env python3 而不是 #!/usr/bin/python3?

  • #!/usr/bin/python3:写死Python路径,如果系统装在非标准位置或使用虚拟环境,脚本运行失败
  • #!/usr/bin/env python3:推荐用法,会自动查找系统PATH中的python3,兼容性最强

虚拟环境场景下,后者能自动使用虚拟环境的Python版本,跨系统迁移也无需修改脚本头。

补充:交互式模式#

终端输入python3进入交互式解释器,输入一行执行一行,适合临时测试小段代码、理解语言特性:

terminal
python3
>>> x = 10
>>> y = 20
>>> print(x + y)
30
>>> exit()

按Ctrl+D或输入exit()退出交互模式。


1.3 语法速通:运维必备核心语法(对照Shell讲解)#

如果你已经掌握Shell,这部分会非常好理解——核心逻辑(条件、循环、函数)完全相通,只是语法格式不同。我们全程对照Shell语法讲解,帮你快速迁移知识。

1.3.1 变量与基础数据类型#

变量定义规则#

  • Shell:name="张三",等号两边绝对不能有空格
  • Python:name = "张三",等号两边推荐加空格(规范写法,PEP8标准)

命名规则和Shell基本一致:由字母、数字、下划线组成,不能以数字开头,区分大小写。

Python变量命名规范

遵循PEP8标准提升代码质量:

  • 常量全大写:MAX_RETRIES = 3
  • 变量小写加下划线:server_name, log_path
  • 避免单字母(i除外):用index替代x
  • 避免和内置函数重名:不用list, dict, file作变量名

运维高频核心数据类型#

  1. 字符串(str):文本内容,单引号/双引号效果一致
string_demo.py
name = "运维工程师"
job = 'DevOps'
# 字符串拼接,对应Shell的 ${a}${b}
msg = "你好," + name
# Python推荐用f-string(格式化字符串),比+拼接更灵活
server = "web01"
ip = "192.168.1.10"
info = f"服务器{server}的IP是{ip}"
print(info) # 输出:服务器web01的IP是192.168.1.10
  1. 整数(int):数字,直接书写即可
int_demo.py
age = 25
cpu_threshold = 80
disk_free = 100_000 # Python 3.6+支持下划线增加可读性
# 直接算术运算,对应Shell的 $(( ))
sum_val = 10 + 20
quotient = 100 // 10 # 整除
remainder = 100 % 3 # 取余
  1. 列表(list):对应Shell的索引数组,存储一组有序数据
list_demo.py
# 定义列表,对应Shell的 services=("nginx" "mysql" "redis")
services = ["nginx", "mysql", "redis"]
# 访问元素,下标从0开始,对应Shell的 ${services[0]}
print(services[0]) # 输出 nginx
# 获取长度,对应Shell的 ${#services[@]}
print(len(services)) # 输出 3
# 追加元素,对应Shell的 services+=("tomcat")
services.append("tomcat")
# 遍历列表
for svc in services:
print(svc)
# 列表切片(强大功能,Shell没有直接对应)
print(services[1:3]) # 输出 ['mysql', 'redis']
  1. 字典(dict):对应Shell的关联数组,键值对结构
dict_demo.py
# 定义字典,对应Shell的 declare -A server_info
server_info = {
"ip": "192.168.1.100",
"hostname": "web01",
"role": "nginx"
}
# 按键取值,对应Shell的 ${server_info["ip"]}
print(server_info["ip"]) # 输出 192.168.1.100
# 新增/修改键值
server_info["status"] = "running"
# 遍历字典
for key, value in server_info.items():
print(f"{key}: {value}")
# 判断键是否存在
if "port" in server_info:
print(server_info["port"])
else:
print("键不存在")

1.3.2 条件判断#

语法核心差异#

  • Shell:if [ 条件 ]; then ... fi,靠fi标记结束
  • Python:if 条件:,靠缩进区分代码块(统一4个空格),无结束关键字

运算符对照表#

功能Shell写法Python写法
大于-gt>
小于-lt<
等于-eq(数值)/ =(字符串)==(通用)
不等于-ne / !=!=
大于等于-ge>=
小于等于-le<=
逻辑与-aand
逻辑或-oor
逻辑非!not
文件存在[ -f file ]os.path.exists(file)
目录存在[ -d dir ]os.path.isdir(dir)
字符串非空[ -n "$str" ]if str:

多分支示例#

condition_demo.py
score = 85
if score >= 90:
print("优秀")
elif score >= 80:
print("良好")
elif score >= 60:
print("及格")
else:
print("不及格")
# 运维常见的服务状态检查
status = "running"
if status == "running":
print("服务正常")
elif status == "stopped":
print("服务已停止")
else:
print("服务异常")
新手第一高频坑

缩进错误是Python初学者最常见的失误。Python严格要求同一层级代码对齐,统一用4个空格,绝对禁止混用Tab和空格。许多编辑器Tab默认是8个空格,容易造成混乱。建议:

  • 编辑器设置 Tab = 4个空格自动转换
  • 开启显示空白符(可视化缩进问题)
  • 使用IDE的自动格式化工具(Ctrl+Shift+F)

1.3.3 循环结构#

break、continue的用法和Shell完全一致:break终止整个循环,continue跳过当前一轮。

for循环(运维最高频)#

用于批量遍历列表、序列,对应Shell的for i in xxx。

for_loop_demo.py
services = ["nginx", "mysql", "redis"]
for svc in services:
print("正在检查服务:", svc)
# 运维场景:批量检查多个服务
for svc in services:
if svc == "nginx":
print(f"重启 {svc}...")
# 这里调用重启命令
continue
print(f"检查 {svc} 状态")

range()函数:生成连续数字序列,对应Shell的{1..10}

range_demo.py
# 遍历1到10(range左闭右开,10不包含)
for i in range(1, 11):
print(i)
# 从0开始,步长为2
for i in range(0, 20, 2):
print(i) # 输出 0, 2, 4, 6, ... 18
# 运维场景:重试机制
for attempt in range(1, 4):
print(f"第 {attempt} 次尝试连接...")
# 连接逻辑
if attempt == 3:
print("连接失败,最后一次尝试")

while循环#

条件为真就持续循环,用法和Shell完全一致。

while_loop_demo.py
i = 1
while i <= 5:
print("第", i, "次检测")
i = i + 1
# 运维场景:监控告警循环
retry_count = 0
while retry_count < 3:
try:
# 执行风险操作
result = connect_to_server()
break # 成功则退出循环
except Exception as e:
retry_count += 1
print(f"连接失败,准备第 {retry_count} 次重试")

1.3.4 函数定义#

语法核心差异#

  • Shell:函数名() { ... },参数靠$1/$2接收,return只能返回0-255状态码
  • Python:def 函数名(参数):,靠缩进区分函数体,return可以返回任意类型数据

带参数带返回值示例#

function_demo.py
# 定义加法函数
def add(a, b):
result = a + b
return result
# 调用并接收返回值
sum_result = add(10, 20)
print(sum_result) # 输出 30
# 运维场景:检查端口是否开放
def check_port(host, port):
"""检查服务器指定端口是否可达"""
try:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((host, port))
sock.close()
return result == 0 # 返回True/False
except Exception as e:
print(f"检查端口异常: {e}")
return False
# 调用
if check_port("192.168.1.10", 22):
print("SSH服务可达")
else:
print("SSH服务不可达")
Python函数的核心优势

相比Shell的状态码返回,Python函数的return更灵活强大:

  • 可返回字符串、列表、字典等复杂数据结构
  • 支持多个返回值:return success, error_msg, result_data
  • 支持None表示操作失败,无需特殊的数字编码
  • 支持异常处理(try/except),比Shell的error handling优雅得多

这些特性让Python实现复杂业务逻辑时,代码更简洁、更易维护。


1.4 实战上手:第一个运维脚本——批量重命名文件#

我们来写第一个实用的运维脚本:批量给指定目录下的.txt文件加上当前日期前缀,比如test.txt变成20260706_test.txt。这是运维日常高频需求,用Python实现逻辑清晰、兼容性好。

完整脚本代码#

batch_rename.py
#!/usr/bin/env python3
# 功能:批量给txt文件添加日期前缀
import os
from datetime import datetime
# ========== 配置项 ==========
target_dir = "./test_files" # 目标目录
date_prefix = datetime.now().strftime("%Y%m%d") # 生成日期前缀,如20260706
# ========== 前置检查 ==========
if not os.path.isdir(target_dir):
print(f"错误:目标目录 {target_dir} 不存在")
exit(1)
# ========== 批量重命名 ==========
count = 0
for filename in os.listdir(target_dir):
# 只处理 .txt 后缀的文件
if filename.endswith(".txt"):
# 拼接完整路径,自动处理分隔符
old_path = os.path.join(target_dir, filename)
new_filename = f"{date_prefix}_{filename}"
new_path = os.path.join(target_dir, new_filename)
# 执行重命名
os.rename(old_path, new_path)
print(f"已重命名:{filename} -> {new_filename}")
count += 1
print(f"\n处理完成,共重命名 {count} 个文件")

关键代码说明#

  1. import os:导入系统操作核心库,对应Shell的内置文件命令
  2. datetime.now().strftime("%Y%m%d"):生成日期字符串,对应Shell的date +%Y%m%d
  3. os.path.isdir():判断目录是否存在,对应Shell的[ -d ]
  4. os.listdir():列出目录下所有文件名,对应Shell的ls
  5. os.path.join():安全拼接路径,自动适配不同系统的分隔符
  6. os.rename():重命名文件,对应Shell的mv
测试提示

运行前先新建test_files目录,放入几个测试txt文件,避免直接在生产目录操作:

terminal
mkdir test_files
touch test_files/log1.txt test_files/report.txt
python3 batch_rename.py
ls test_files/

1.5 核心基础:文件与目录自动化操作(os模块核心用法)#

运维80%的场景都在和文件、目录打交道,os模块就是Python中对应Shell文件操作的核心工具库。下面按场景分类讲解高频用法,每个都对应Shell命令,方便对照记忆。

1.5.1 路径与属性判断#

对应Shell的文件测试表达式:

功能Shell写法Python写法
判断文件/目录是否存在[ -e path ]os.path.exists(path)
判断是否为目录[ -d path ]os.path.isdir(path)
判断是否为普通文件[ -f path ]os.path.isfile(path)
判断是否为符号链接[ -L path ]os.path.islink(path)
获取文件大小(字节)stat -c %s pathos.path.getsize(path)
获取绝对路径realpath pathos.path.abspath(path)
获取文件夹名basename /path/to/diros.path.basename(path)
获取路径部分dirname /path/to/fileos.path.dirname(path)

1.5.2 目录操作#

对应Shell的mkdir、cd、pwd等命令:

dir_operations.py
import os
# 获取当前工作目录,对应 pwd
current_dir = os.getcwd()
print(f"当前目录:{current_dir}")
# 切换工作目录,对应 cd /opt
os.chdir("/opt")
# 创建单个目录,对应 mkdir data
os.mkdir("data")
# 递归创建多级目录,对应 mkdir -p a/b/c
os.makedirs("a/b/c")
# 删除空目录,对应 rmdir data
os.rmdir("data")
# 列出目录内容,对应 ls
items = os.listdir(".")
for item in items:
print(item)
目录删除操作

os.rmdir()只能删除空目录,删除非空目录(对应rm -rf)使用shutil模块:

remove_dir.py
import shutil
# 删除非空目录及所有内容,等价于 rm -rf
# ⚠️ 生产环境慎用,无法恢复
shutil.rmtree("target_directory")
# 更安全的做法:先检查再删除
import os
target = "target_directory"
if os.path.exists(target):
if os.path.isdir(target):
shutil.rmtree(target)
print(f"已删除目录:{target}")
else:
os.remove(target)
print(f"已删除文件:{target}")

1.5.3 文件操作#

对应Shell的cp、mv、rm命令:

file_operations.py
import os
import shutil
# 复制文件,对应 cp src.txt dst.txt
shutil.copy("src.txt", "dst.txt")
# 复制文件并保留元数据(修改时间等),对应 cp -p
shutil.copy2("src.txt", "dst.txt")
# 递归复制目录,对应 cp -r src_dir dst_dir
shutil.copytree("src_dir", "dst_dir")
# 移动/重命名文件,对应 mv old new
# shutil.move更安全,可跨分区
shutil.move("old.txt", "new.txt")
# 删除文件,对应 rm file.txt
os.remove("file.txt")
# 删除非空目录,对应 rm -rf
shutil.rmtree("directory")

1.5.4 遍历目录#

1. 单层遍历:os.listdir()#

只遍历目标目录第一层,不进入子目录,对应ls。

list_dir.py
# 列出当前目录下所有文件和目录
for item in os.listdir("."):
full_path = os.path.join(".", item)
if os.path.isdir(full_path):
print(f"[目录] {item}")
else:
print(f"[文件] {item}")

2. 递归遍历:os.walk()#

递归遍历所有子目录,对应find的遍历能力,是日志分析、批量文件处理的核心。

walk_dir.py
# 递归查找/var/log下所有.log文件,等价于 find /var/log -type f -name "*.log"
for root, dirs, files in os.walk("/var/log"):
# root: 当前遍历到的目录路径
# dirs: 当前目录下的子目录列表
# files: 当前目录下的文件列表
for file in files:
if file.endswith(".log"):
full_path = os.path.join(root, file)
# 获取文件大小
size = os.path.getsize(full_path)
print(f"{full_path} ({size} bytes)")
# 运维场景:查找所有超过1GB的日志文件并清理
import os
for root, dirs, files in os.walk("/var/log"):
for file in files:
if file.endswith(".log"):
full_path = os.path.join(root, file)
size = os.path.getsize(full_path)
# 1GB = 1073741824 bytes
if size > 1073741824:
print(f"清理大日志:{full_path} ({size/1024/1024:.2f}MB)")
os.remove(full_path)
os.walk()运维妙用

os.walk()在日常运维中非常高频:

  • 日志清理:递归找出超大日志文件,自动删除或压缩
  • 备份验证:遍历备份目录,校验文件完整性
  • 配置文件扫描:查找所有配置文件,批量修改配置项
  • 权限检查:递归检查目录权限,修复不合规权限

1.6 本章小结 + 入门动手练习#

1.6.1 本章知识点梳理#

  1. 选型认知:Shell适合简单命令拼接与快速自动化,Python适合复杂逻辑、数据处理与工具开发,两者配合效率最高。关键决策:脚本超过200行或维护期限超过6个月,优先选Python。

  2. 环境运行:Linux默认预装Python3,通过pip3安装第三方库,脚本支持解释器执行和加权限直接运行两种方式。国内用户配置清华源大幅加速包下载。

  3. 核心语法:

    • 变量:等号两边可加空格,核心类型为字符串、整数、列表、字典,推荐使用f-string进行字符串格式化
    • 条件判断:靠缩进区分代码块,使用标准比较符与and/or/not逻辑运算,掌握文件/目录存在性判断
    • 循环:for循环用于批量遍历,range()生成数字序列,while循环用于条件持续,break/continue用法与Shell一致
    • 函数:def关键字定义,return可返回任意类型数据(比Shell的0-255状态码灵活得多),支持异常处理
  4. 文件目录操作:os模块为核心,覆盖所有Shell文件操作命令,os.walk()可实现递归目录遍历,是日志处理、批量操作的利器。

1.6.2 动手练习(巩固所学)#

练习1:日志文件分类

编写脚本,遍历/var/log目录,按照日期分类日志文件到不同目录:

/var/log/
├── 2025-01/
│ ├── syslog
│ └── auth.log
├── 2025-02/
└── ...
思路提示
  1. 使用os.walk()递归遍历日志目录
  2. 通过文件修改时间os.path.getmtime()提取日期
  3. 根据日期用datetime.fromtimestamp()转换成年月
  4. 用os.makedirs()创建对应的年月目录
  5. 用shutil.move()移动文件到对应目录

练习2:服务进程监控脚本

编写脚本实现以下逻辑:

  • 定义要监控的服务列表(nginx, mysql, redis等)
  • 逐一检查服务是否运行
  • 未运行则自动启动,并记录日志
思路提示
  1. 使用os.system()或subprocess模块执行系统命令
  2. 通过systemctl status判断服务状态
  3. 用函数实现模块化,方便复用
  4. 用列表存储服务名称,循环检查
  5. 未运行则systemctl start启动

这两个练习涵盖了本章所有核心知识点,完成它们意味着你已掌握Python运维脚本的基础能力。

Python第一章 入门筑基:从零上手编写运维脚本
https://www.6ixblog.site/posts/linux-python-1/
作者
Licwic
发布于
2025-06-03
许可协议
CC BY-NC-SA 4.0