不同 Linux 发行版中 `df` 的输出格式不同

Pid*_*una 4 linux centos ubuntu df

在 Ubuntu 中,此命令的输出

df --exclude={tmpfs,devtmpfs,squashfs,overlay} | sed -e /^Filesystem/d | awk '{print $6 " " $1 " " $3 " " $4 " " $5}'
Run Code Online (Sandbox Code Playgroud)

是:

/ /dev/mapper/dockerVG-rootLV 8110496 40591632 17%
/dockerssd /dev/mapper/ssdVG-ssdLV 214133656 274642488 44%
/dockerhdd /dev/mapper/hddVG-hddLV 83278236 1385191240 6%
/var/lib/docker /dev/mapper/hddVG-dockerLV 76046204 412729940 16%
Run Code Online (Sandbox Code Playgroud)

这就是我需要的。

在 CentOS 6 上我得到这个输出:

 /dev/mapper/vg_rproxy-lv_root
 51475068 43192316 12% /
/boot /dev/sda1 82688 379364 18%
 /dev/mapper/vg_rproxy-lv_home
 77349888 73119692 1% /home
Run Code Online (Sandbox Code Playgroud)

一团糟。

CentOS 6 的完整输出:

$ df
Filesystem           1K-blocks    Used Available Use% Mounted on
/dev/mapper/vg_rproxy-lv_root
                      51475068 5661336  43192292  12% /
tmpfs                   957140       0    957140   0% /dev/shm
/dev/sda1               487652   82688    379364  18% /boot
/dev/mapper/vg_rproxy-lv_home
                      77349888  294352  73119692   1% /home
Run Code Online (Sandbox Code Playgroud)

问题是什么?我该如何解决?

Kam*_*ski 10

tl;博士

使用df -P.


完整答案

/dev/mapper/vg_rproxy-lv_root并且/dev/mapper/vg_rproxy-lv_home是相对较长的字符串。它出现df在 CentOS决定将它们的条目拆分为两行时,当您想进一步解析输出时,这会破坏逻辑。

在狭窄的终端中,这可能是一件好事,即使水平空间有限,也能创建半列化的人类可读输出。我希望在df写入非 tty(在您的情况下为管道)时不会发生这种情况。

df如果Filesystem列中的条目很长,可能在 Ubuntu 中的行为类似;也许你只是没有经历过这一点,因为你的相对较短。我不知道,这不重要。重要的df是 POSIX 工具并且应该遵循规范。但规范明确指出:

历史df实现的默认输出差异很大。因此,有必要以宽松的方式描述默认输出,以适应所有已知的历史实现,并添加一个可移植选项 ( -P) 以提供可移植格式的信息。

关于选项:

-P
以 STDOUT 部分中描述的格式生成输出。

最后是 STDOUT 部分的相关部分(重点是我的):

实现方式可以调整标题行和各个数据行的间距,使信息按列有序呈现。

剩余的输出-P由以下各项组成的每个指定的文件系统信息中的一个线。这些行的格式如下:

"%s %d %d %d %d%% %s\n", <file system name>, <total space>,
    <space used>, <space free>, <percentage used>,
    <file system root>
Run Code Online (Sandbox Code Playgroud)

所以df允许输出任何东西,除非你使用-P. 如果没有-P一些实现df可能会产生可预测和可解析的输出,其他的......不是那么多。他们的行为可能会或可能不会被记录得足够好。因此,一般而言,在解析输出df时应始终使用-P.

只需添加-P可能就足以解决您的特定问题。

注意-P仅控制格式。整体 POSIX 规范仅适用于 POSIX 语言环境。此外,现代实现df倾向于默认使用 1024 字节的块,而 POSIX 声明默认值为 512。在我的 Debian 10 中df,GNU coreutilsPOSIXLY_CORRECT在环境中设置时回退到 POSIX 默认值。便携地,您可以使用-k.

这是一个可移植的命令,它产生(几乎)可解析的输出:

LC_ALL=POSIX df -Pk
Run Code Online (Sandbox Code Playgroud)

几乎可以解析,因为Filesystem我认为列中的条目可能包含空格;尽管在配置合理的操作系统中,它们没有。

您可以省略LC_ALL=POSIX并仍然得到预期的结果,但通常它应该在那里进行解析。例如,在我的波兰语语言环境中,您sed -e /^Filesystem/d无法完成它的工作,因为我从我的df. LC_ALL=POSIX解决了这个问题。我个人的偏好仍然是不依赖标题中的任何内容。我会使用sed 1dtail -n +2; 或将任务委托给awk,因为awk已经在您的管道中。这将是:

LC_ALL=POSIX df -Pk --exclude={tmpfs,devtmpfs,squashfs,overlay} \
| awk 'NR>1 {print $6 " " $1 " " $3 " " $4 " " $5}'
Run Code Online (Sandbox Code Playgroud)

最后--exclude=不是一个便携的选择。显然,它在所讨论的两个系统中都适用于您,但它可能不适用于其他系统。

  • 或者使用`findmnt --df --json` 来利用广泛支持的可解析格式。 (2认同)