Appearance
Python基础语法
Python 运维脚本常用于处理分支逻辑、循环任务、异常和结构化数据,基础语法覆盖变量、类型、条件、循环、函数和脚本入口。
一、运行脚本
Python 3 是标准。老系统上可能还有 Python 2 遗留,写脚本时确认实际命令指向。
bash
uv run python script.py如果是服务器环境没有 uv,再按机器上的实际情况用 python3 script.py。本地默认还是走 uv,避免不同 Python 环境混在一起。
python
#!/usr/bin/env python3
# 上面这行让系统知道用 python3 执行,chmod +x 之后可以 ./script.py
print("hello")交互模式 python3 可以临时验证语法,但运维脚本写成文件更常见。
二、变量与类型
Python 不需要声明类型,赋值即定义。
python
name = "nginx" # str
port = 80 # int
rate = 3.14 # float
enabled = True # bool
result = None # NoneType,表示"空"或"未赋值"type() 可以查看变量类型,调试时偶尔用。
python
print(type(port)) # <class 'int'>变量名用小写加下划线(snake_case)。运维脚本通常会传给别人维护,命名规整一点,后面回来看少猜一次。
三、字符串
运维脚本里字符串用得最多,拼路径、拼命令、拼日志。
3.1 f-string
Python 3.6+ 支持 f-string,可以在字符串里嵌变量。
python
service = "nginx"
port = 80
msg = f"{service} is running on port {port}"
print(msg) # nginx is running on port 80花括号里可以放表达式:
python
count = 5
print(f"retry count: {count + 1}") # retry count: 6老代码里可能见到 .format() 或 % 格式化,功能一样,只是写法旧。
3.2 常用方法
python
s = " Hello, World! "
s.strip() # 去首尾空白,处理用户输入时必用
s.lower() # " hello, world! "
s.upper() # " HELLO, WORLD! "
s.split(",") # [' Hello', ' World! '],按逗号切分
s.replace("World", "Python") # 替换
"nginx".startswith("ng") # True
"script.py".endswith(".py") # True3.3 多行字符串
python
log = """2024-01-01 12:00:00 INFO nginx started
2024-01-01 12:00:01 ERROR disk full"""
# 三引号保留换行,适合处理日志或写多行配置四、运算符
算术和比较跟其他语言基本一样,记几个 Python 特有的。
python
# 算术
10 // 3 # 3,整除(向下取整)
10 % 3 # 1,取余
2 ** 3 # 8,幂运算
# 比较
1 == 1 # True
1 != 2 # True
# 逻辑
True and False # False
True or False # True
not True # False
# 成员判断,运维里常用
"nginx" in ["nginx", "mysql", "redis"] # True
"php" not in ["nginx", "mysql"] # True五、条件判断
if / elif / else,注意用缩进而不是花括号。
python
cpu_usage = 85
if cpu_usage >= 90:
status = "critical"
elif cpu_usage >= 70:
status = "warning"
else:
status = "ok"
print(f"CPU: {cpu_usage}%, status: {status}")条件可以是任意表达式,Python 里 0、""、[]、None 都算 False。
python
result = None
if not result:
print("result is empty") # 会执行多个条件组合:
python
if cpu_usage > 80 and disk_usage > 90:
print("需要处理")三元表达式,简单判断可以一行写:
python
level = "high" if cpu_usage > 80 else "normal"六、循环
6.1 for 循环
遍历列表是运维脚本最常见的用法。
python
services = ["nginx", "mysql", "redis"]
for svc in services:
print(f"checking {svc}")range() 生成数字序列:
python
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(1, 6): # 1, 2, 3, 4, 5
print(i)遍历字典时拿到 key 和 value:
python
config = {"host": "10.0.0.1", "port": 3306, "user": "root"}
for key, value in config.items():
print(f"{key} = {value}")enumerate() 同时拿到索引和值:
python
for i, svc in enumerate(services):
print(f"{i}: {svc}")6.2 while 循环
适合不确定次数的场景,比如重试。
python
import time
retry = 0
max_retry = 3
while retry < max_retry:
print(f"attempt {retry + 1}")
# 这里放实际的连接/检查逻辑
retry += 1
time.sleep(1)6.3 break 和 continue
break 跳出循环,continue 跳过本次。
python
for svc in services:
if svc == "mysql":
continue # 跳过 mysql
print(f"checking {svc}")七、函数
用 def 定义,return 返回值。
python
def check_port(host, port):
"""检查端口是否可达"""
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2)
result = sock.connect_ex((host, port))
sock.close()
return result == 0 # 返回 True/False
if check_port("127.0.0.1", 22):
print("SSH OK")7.1 默认参数
python
def run_cmd(cmd, timeout=30, verbose=False):
"""timeout 给默认值 30 秒,调用时可以不传"""
print(f"running: {cmd}, timeout: {timeout}")
if verbose:
print("verbose mode on")
run_cmd("uptime") # timeout=30, verbose=False
run_cmd("df -h", timeout=60) # verbose 仍然是 False
run_cmd("ls", verbose=True) # timeout 仍然是 307.2 *args 和 **kwargs
不确定参数个数时用。
python
def log(level, *tags, **extra):
# *tags 收集为元组,**extra 收集为字典
tag_str = ",".join(tags)
print(f"[{level}] {tag_str} {extra}")
log("ERROR", "nginx", "disk", node="web01", region="cn")
# [ERROR] nginx,disk {'node': 'web01', 'region': 'cn'}7.3 返回多个值
Python 函数可以返回元组,解构赋值。
python
def get_disk_usage(mount_point):
import shutil
total, used, free = shutil.disk_usage(mount_point)
return total, used, free
total, used, free = get_disk_usage("/")
print(f"used: {used // (1024**3)} GB")八、异常处理
脚本跑线上出错不能只留一屏堆栈。try / except 至少要把错误位置和原因打清楚。
python
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"error: {e}")捕获多种异常:
python
try:
with open("/etc/hosts") as f:
data = f.read()
num = int(data)
except FileNotFoundError:
print("file not found")
except ValueError:
print("cannot convert to int")捕获所有异常(谨慎用,可能吞掉有用的报错):
python
try:
risky_operation()
except Exception as e:
print(f"unexpected error: {e}")finally 无论如何都会执行,适合清理资源:
python
conn = None
try:
conn = get_connection()
do_something(conn)
except Exception as e:
print(f"error: {e}")
finally:
if conn:
conn.close() # 不管成功失败都关连接else 子句:没有异常时才执行。
python
try:
value = int("42")
except ValueError:
print("parse failed")
else:
print(f"parsed: {value}") # 没异常才到这里主动抛异常,写工具函数时偶尔用:
python
def validate_port(port):
if not (1 <= port <= 65535):
raise ValueError(f"invalid port: {port}")九、退出码
运维脚本需要返回退出码给 shell,sys.exit()。
python
import sys
def main():
if not check_service():
print("service check failed", file=sys.stderr)
sys.exit(1) # 非零退出码表示失败,shell 判断 $? 时用
print("all good")
sys.exit(0) # 零表示正常
main()没有 sys.exit() 的话,脚本跑完退出码是 0。但显式写出来更清楚,尤其是脚本有多条执行路径时。
十、注释与文档字符串
单行注释用 #。
python
# 跳过已经处理过的文件
if filename in processed:
continue函数的 docstring 用三引号,写清楚参数和返回值,IDE 和 help() 能读到:
python
def parse_log_line(line):
"""解析一行日志,返回 (timestamp, level, message) 元组"""
parts = line.strip().split(None, 2) # None 表示按任意空白分割,最多分 3 段
if len(parts) < 3:
return None
return parts[0], parts[1], parts[2]