lsblk -P 是解析块设备信息最规范的机器可读方式,输出键值对(如 NAME="sda" TYPE="disk"),天然适配自动化工具;核心用于云盘初始化,需筛选 TYPE="disk"、RO="0"、MOUNTPOINT="" 且 SIZE≥阈值的裸盘。

lsblk -P 是 Linux 下解析块设备信息最规范的机器可读方式,输出形如 NAME="sda" TYPE="disk" SIZE="100G" RO="0" RM="0" MODEL="Virtual_disk" 的键值对,天然适配 shell 脚本、Ansible、Python 等自动化工具。用于云盘初始化(如识别新挂载的数据盘、跳过系统盘、自动分区/格式化/挂载)非常可靠。
理解 lsblk -P 输出结构与关键字段
执行 lsblk -P -o NAME,TYPE,SIZE,RO,RM,MOUNTPOINT,MODEL 可定制输出字段。核心字段含义:
-
NAME:设备名(如
sdb、nvme0n1),不含路径,适合拼接/dev/ -
TYPE:必须为
disk(跳过part、rom、loop)才能作为原始云盘处理 -
RO:只读标志,
RO="0"表示可写(必须检查,避免误操作只读设备) -
RM:可移动标志,云盘通常为
RM="0";部分云环境(如 AWS EBS)可能为RM="1",需按实际策略判断 -
MOUNTPOINT:为空(
MOUNTPOINT="")表示未挂载,是“待初始化”云盘的关键判据 -
SIZE:带单位(如
"100G"),可用awk或numfmt提取纯数值做容量判断(例如只处理 ≥20G 的盘)
Shell 脚本中安全提取并过滤目标云盘
用 while IFS= read -r line 逐行解析,配合 eval 将 Key=Value 转为变量(注意引号保护):
lsblk -P -o NAME,TYPE,SIZE,RO,RM,MOUNTPOINT | while IFS= read -r line; do
[ -z "$line" ] && continue
eval "$line" # 将 NAME="sdb" TYPE="disk" → 变量 $NAME $TYPE 等
if [[ $TYPE == "disk" && $RO == "0" && -z $MOUNTPOINT ]]; then
dev="/dev/$NAME"
size_gb=$(echo "$SIZE" | sed 's/[A-Z]//g') # 去掉单位,粗略比较(如 "50G" → "50")
if (( $(echo "$size_gb >= 20" | bc -l) )); then
echo "发现待初始化云盘: $dev ($SIZE)"
# 后续执行 parted/mkfs/mount...
fi
fi
done
⚠️ 注意:while 循环在管道中会启用子 shell,变量无法回传。生产脚本建议改用进程替换:while ...; do ...; done ,确保变量作用域可控。
对接自动化部署(Ansible / Python 示例)
Ansible 中直接解析: 使用 community.general.lsblk 模块(底层即调用 lsblk -P),返回结构化 JSON:
- name: 获取裸盘列表
community.general.lsblk:
output_fields: "NAME,TYPE,SIZE,RO,RM,MOUNTPOINT"
register: blkinfo
- name: 初始化未挂载的数据盘
block:
- filesystem: fstype: xfs dev: "/dev/{{ item.NAME }}"
- mount: path: "/data/{{ item.NAME }}" src: "/dev/{{ item.NAME }}" fstype: xfs state: mounted loop: >- {{ blkinfo.blkdevs | selectattr('TYPE', 'equalto', 'disk') | selectattr('RO', 'equalto', '0') | selectattr('MOUNTPOINT', 'equalto', '') | list }}
Python 中解析(推荐用 subprocess + shlex):
import subprocess, shlex
<p>result = subprocess.run(['lsblk', '-P', '-o', 'NAME,TYPE,SIZE,RO,RM,MOUNTPOINT'],
capture_output=True, text=True)
disks = []
for line in result.stdout.strip().split('\n'):
if not line.strip():
continue</p><h1>安全拆分 Key="Value"(支持含空格的 Value)</h1><pre class="brush:php;toolbar:false;">kv_pairs = shlex.split(line)
attrs = {}
for kv in kv_pairs:
if '=' in kv:
k, v = kv.split('=', 1)
attrs[k] = v.strip('"\'')
if (attrs.get('TYPE') == 'disk' and
attrs.get('RO') == '0' and
not attrs.get('MOUNTPOINT')):
disks.append('/dev/' + attrs['NAME'])print("待处理云盘:", disks)
云环境特殊注意事项
不同云平台的设备命名与行为有差异,需针对性适配:
-
AWS EC2:EBS 卷常为
xvdf、nvme1n1,RM="1";建议加MODEL字段过滤(如MODEL="Amazon Elastic Block Store") -
阿里云 ECS:系统盘为
vda,数据盘多为vdb~vdd;注意vdb可能已被 cloud-init 自动挂载,需检查MOUNTPOINT是否为空 -
腾讯云 CVM:NVMe 盘为
nvme0n1,SATA 盘为sdb;部分镜像默认将第二块盘挂载到/data,需确认是否覆盖 - 统一建议:首次运行前加 dry-run 模式(如
--dry-run参数),仅打印将执行的操作,不真实格式化
不复杂但容易忽略:始终用 lsblk -P 而非 lsblk 默认输出,避免因列宽截断、空格错位导致解析失败;所有设备路径拼接前校验 NAME 是否匹配正则 ^[a-z]+[0-9]*$,防注入风险。











