登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

findmnt JSON 输出用于脚本读取的字段选择

来源:17golang原创

时间:2026-09-28 20:29:57 471浏览 收藏

脚本读取 findmnt 时,最稳妥的写法不是对默认表格做 awk 切列,而是同时固定三件事:用 --json 固定格式、用 --list 固定为平铺结构、用 --output 明确字段。对“某个路径落在哪个文件系统”这类任务,通常先选 TARGET,SOURCE,FSTYPE,OPTIONS 四列就够了;需要容量计算时再显式增加 SIZE,USED,AVAIL 并配合 --bytes。

迁移要点
  • 默认输出可能变化,脚本必须显式写出 --output 列表。
  • 只加 --json 仍可能得到树形 children;想让 jq 路径简单稳定,应同时使用 --list。
  • 先判断 findmnt 退出状态,再解析 JSON;“没有匹配项”和“字段为空”不是同一件事。

官方手册:https://man7.org/linux/man-pages/man8/findmnt.8.html

先固定格式、结构和字段三层合同

findmnt 默认以树形表格显示挂载关系,这种输出适合人看,却不适合长期脚本接口。列宽、树形前缀和默认列都不应该成为解析依据。迁移时先写出一条最小命令:

# -J 固定 JSON,-l 关闭树形层级,-o 固定脚本依赖的字段。
findmnt -J -l -o TARGET,SOURCE,FSTYPE,OPTIONS

这四个字段各自承担明确职责:

字段脚本用途什么时候可以不选
TARGET挂载点,通常是路径匹配和结果展示的主键几乎不建议省略
SOURCE设备、卷或网络文件系统来源只判断文件系统类型时可省略
FSTYPEext4、xfs、tmpfs 等文件系统类型完全不关心类型时可省略
OPTIONS合并后的挂载选项,用于检查 ro、rw、noexec 等状态不做挂载策略判断时可省略

如果只需要内核 VFS 选项或文件系统专属选项,可以分别选择 VFS-OPTIONS 与 FS-OPTIONS,不要默认把 OPTIONS 拆字符串后猜测来源。当前机器到底支持哪些列,应查询已安装版本,而不是把网上的一份列清单硬编码进脚本。

# 以机器可读格式列出当前 findmnt 可用于 --output 的列。
findmnt --json --list-columns

# 旧环境若不支持该组合,至少从本机帮助中核对列名。
findmnt --help
findmnt JSON list output 与 TARGET SOURCE FSTYPE OPTIONS 字段合同的静态关系说明图
图1:findmnt 脚本输出合同说明图,格式、结构与字段必须同时固定。

树形 JSON 与平铺 JSON 的读取路径不同

JSON 输出的根对象包含 filesystems。未启用列表模式时,挂载层级可以通过条目中的 children 继续嵌套;启用 --list 后,脚本可以把 .filesystems[] 当作平铺集合读取。这就是为什么只把旧命令后面追加 -J 还不够。

平铺命令的结果结构可以概括为:

{
  "filesystems": [
    {
      "target": "/",
      "source": "/dev/example",
      "fstype": "ext4",
      "options": "rw,relatime"
    }
  ]
}

上面只是解释键名的结构示例,不代表当前机器的真实挂载结果。列名在 JSON 中以小写键出现;脚本仍应以自己传给 --output 的列集合为合同。若业务确实要保留父子挂载关系,就不要加 --list,并让 jq 递归读取可选的 children:

# 树形模式保留 children;recurse 会遍历根条目和所有子挂载。
findmnt -J -o TARGET,SOURCE,FSTYPE |
  jq -r '.filesystems[] | recurse(.children[]?) | [.target, .source, .fstype] | @tsv'

如果需求只是生成资产清单、判断只读挂载或查询一个路径所属的文件系统,平铺结构通常更容易维护。只有当父子挂载关系本身就是业务数据时,才值得让脚本承担递归逻辑。

查询对象要用对应的过滤参数表达

同一个字符串可能既像设备名又像挂载点。为了避免歧义,脚本中应明确使用过滤选项:

问题推荐参数结果特点
这个任意路径属于哪个文件系统--target /path/to/file会从路径向上寻找所属挂载点,最多返回一项
这个目录本身是否就是挂载点--mountpoint /mnt/data只匹配严格挂载点,不向父目录回溯
这个设备挂载到哪里--source /dev/...按挂载源过滤,可能得到多个目标

查询某个应用目录所属文件系统时,可以这样写:

path='/var/lib/app'

# --target 接受任意文件或目录,并查找其所属文件系统。
findmnt -J -l -o TARGET,SOURCE,FSTYPE,OPTIONS --target "$path"

这里不要为了“只要一条”就用文本工具截第一行。--target 本身最多返回一个文件系统条目;若改用 --source,多个挂载目标可能都是有效结果,是否只取第一项应由业务规则决定。

新脚本先判断命令状态,再读取 filesystems

findmnt 有内容可显示时退出值为 0;无匹配、路径不存在或其他错误会返回非零状态。若把命令直接放进不检查状态的管道,脚本可能把“没有挂载信息”误判成“JSON 数组为空”。更稳妥的写法是先捕获输出,再让 jq 检查结构和字段:

#!/usr/bin/env bash
set -u

path=${1:-/var/lib/app}

# 先保存 findmnt 输出并保留它自己的退出状态。
if ! payload=$(findmnt -J -l -o TARGET,SOURCE,FSTYPE,OPTIONS --target "$path"); then
  printf '未找到路径对应的文件系统,或 findmnt 执行失败: %s\n' "$path" >&2
  exit 1
fi

# -e 要求表达式为真;字段缺失时脚本立即失败,而不是继续使用空字符串。
if ! jq -e '
  (.filesystems | length) == 1 and
  (.filesystems[0].target | type == "string") and
  (.filesystems[0].source | type == "string") and
  (.filesystems[0].fstype | type == "string")
' >/dev/null &2
  exit 2
fi

# 最后再提取需要传给后续逻辑的字段。
jq -r '.filesystems[0] | [.target, .source, .fstype, .options] | @tsv' 

OPTIONS 在某些来源或场景下可能为空,因此示例没有强制它必须是字符串。若业务要求检查 ro、rw 或 noexec,应先明确空值是失败、未知还是允许,再写对应条件。

findmnt filesystems 挂载条目字段 children 与 jq 读取关系的静态数据结构说明图
图2:findmnt JSON 数据结构说明图,--list 适合固定读取平铺条目,树形输出可能包含 children。

容量字段必须同时固定单位

要做容量阈值判断时,可以增加 SIZE、USED、AVAIL 和 USE%。默认容量显示使用便于阅读的 K、M、G 等单位,脚本不应自己猜后缀。加上 --bytes 后,SIZE、USED、AVAIL 按字节输出,单位含义才适合数值比较。

# --bytes 把容量统一为字节;字段列表仍由脚本显式声明。
findmnt -J -l --bytes \
  -o TARGET,SOURCE,FSTYPE,SIZE,USED,AVAIL,USE% \
  --target /var/lib/app

即使使用 JSON,也不要跨发行版盲猜值一定是数字类型或字符串类型。最稳妥的方法是在 jq 中按目标环境的实际类型做断言,或者使用 tonumber 明确转换;升级 util-linux 后,把类型检查纳入回归用例。

从旧脚本迁移时逐项回归

迁移不是把 findmnt 后面简单加一个 -J。建议按下面清单逐项核对:

  • 命令包含 --json、--list 和完整的 --output 列表。
  • 脚本从 .filesystems[] 读取,不依赖表格列宽、空格数量或树形字符。
  • 按查询意图选择 --target、--mountpoint 或 --source。
  • 在调用 jq 之前保存并判断 findmnt 的退出状态。
  • 容量计算显式使用 --bytes,升级后复查 JSON 值类型。
  • 多挂载结果不随意取第一条,是否允许多项由业务合同决定。
  • 测试至少覆盖正常挂载点、普通子目录、不存在路径和一个可能多结果的源设备。

相关问题

findmnt -J 为什么还有 children?

-J 只选择 JSON 格式,默认挂载视图仍可以保持树形关系。脚本想读取平铺数组时,再加 --list。

脚本只查挂载点时需要哪些字段?

多数场景从 TARGET,SOURCE,FSTYPE,OPTIONS 开始即可。只有确实要做容量、UUID、传播属性或 VFS/文件系统选项区分时,再增加对应列。

为什么不建议解析 mount 命令的文本输出?

findmnt 提供可定制字段和 JSON 格式,更适合作为脚本接口;显式字段合同也更容易在系统升级时做回归检查。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>