Bash脚本使用sed提取lsblk输出的sd/nvme磁盘设备存入数组
失效原因
你之前写的sed命令不生效核心是几个问题:
- 默认sed使用基础正则(BRE)模式,你写的
()、+、?、|属于扩展正则元字符,不加转义、不加-E参数的话会被当成普通字符匹配,完全达不到预期 - 没有跳过lsblk输出的第一行表头,容易把无关内容匹配进来
- 正则逻辑写错:比如
sd\.*里的\.是匹配字面意义的点号,不是任意字符;(sd | nv)里加了多余空格,匹配的是「sd+空格」或者「空格+nv」的内容,和实际设备名格式不符 - 没有做字段截取,容易把后面的容量、挂载点等冗余内容带进来,也没处理尾部空格问题
最优实现(无正则兼容坑)
根本不需要写复杂正则硬抠输出,lsblk原生支持自定义输出字段、关闭表头,是最稳定的写法:
# 直接将符合要求的设备名存入bash数组 disks=($(lsblk --nodeps -n -o NAME | grep -E '^(sd|nvme)'))
参数说明:
-n:不输出表头行,自动跳过第一行NAME MAJ:MIN...的内容-o NAME:仅输出设备名一列,不会带其他冗余字段,天然不存在尾部空格问题grep -E '^(sd|nvme)':用扩展正则匹配行首为sd或nvme的条目,精准命中你需要的两类块设备
执行完可以用下面的命令验证数组内容:
# 遍历输出数组内所有设备 for dev in "${disks[@]}"; do echo "识别到磁盘设备: $dev" done
对应你给出的lsblk输出,数组内会存入三个元素:sda、sdb、nvme0n1,完全符合预期。
纯sed实现方案
如果不想调用grep,用sed也可以实现同样效果,记得加-E启用扩展正则:
disks=($(lsblk --nodeps -n -o NAME | sed -n -E '/^(sd|nvme)/p'))
如果必须从默认全列的lsblk输出中提取(不推荐,不同版本列对齐变化可能导致匹配失效),写法如下:
disks=($(lsblk --nodeps | sed -n -E '1d; s/^[[:space:]]*((sd|nvme)[a-z0-9]+)[[:space:]]+.*/\1/p'))
逻辑说明:
1d:删除第一行表头- 匹配行首空白后以sd/nvme开头的设备名,将整行替换为匹配到的设备名,自动剔除后面所有冗余内容和前后空格
注意事项
- 不要用硬抠默认格式化输出的方式解析lsblk结果,优先用工具自带的输出控制参数,兼容性比自己写正则高很多,不会因为版本差异、列宽变化导致匹配错误
- 常规场景下直接用
disks=($(命令输出))的方式赋值数组即可,bash会自动按空白(换行、空格、tab)分割元素,如果存在特殊设备名(正常块设备命名不会出现空格等特殊字符),可以提前设置IFS=$'\n'限定仅按换行分割 - 不要尝试通过解析
/dev下的ls结果拿设备,容易把分区、设备映射器的其他条目混进来,lsblk输出的是内核识别到的真实块磁盘,结果更准确
内容的提问来源于stack exchange,提问作者Rich_F
相关产品推荐
相关产品推荐

