stat 命令详解与参数实测(Ubuntu 22.04)

stat 命令逐参数实测详解:默认输出 inode 元数据逐行解读、-c 常用格式符逐个实测、-f 文件系统状态、-t 简洁模式、-L 跟随软链、--printf 与 --cached,附 atime/mtime/ctime 三种时间戳 touch 与 cat 实测对比,全部命令与回显在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。

Linux命令Linux系统UbuntuUbuntu 22.04命令行文件管理2026/10/15

stat 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 GNU stat 的每一个参数——默认输出的 inode 元数据全景逐行解读、-c 十余个常用格式符定制输出、-f 文件系统状态、-t 简洁单行、-L 跟随软链、--printf 转义输出、--cached 缓存控制,并用实测厘清 atime/mtime/ctime 三种时间戳的差异,全部命令与回显已在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。

一、环境信息

本篇所有命令与回显均在以下环境实测采集,读者在同等版本环境可逐条复现。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • stat 版本:GNU coreutils 8.32(stat --version 实测),coreutils 基础工具集,Ubuntu 22.04 默认预装,无需额外安装
  • 演示目录:/root/demo/stat/
  • 测试数据:note.txt(普通文本文件)、demo.sh(可执行脚本)、echo.bin(复制 /bin/echo 得到的 ELF 二进制文件)、note.lnk(软链接)、subdir/(目录),另有 ts.txt(时间戳演示用)、note-hard.txt(硬链接演示用)

二、命令概览

stat 的职责是展示文件或文件系统的 inode 级元数据:大小、块占用、inode 号、硬链接数、权限、属主以及四类时间戳。与 ls -l 相比,stat 输出更完整(含 Birth 创建时间与纳秒级时间戳),且提供 -c 格式符体系供脚本精确取值。

2.1 语法与测试数据准备

stat 的语法为 stat [OPTION]... FILE...(源自 --help 原文),常用形态是 stat 文件 看全景、stat -c 格式 文件 在脚本中取单项值。先准备一套覆盖典型文件形态的演示数据:

mkdir -p /root/demo/stat/subdir
printf 'hello stat\nline two\n' > /root/demo/stat/note.txt
printf '#!/bin/bash\necho "demo script"\n' > /root/demo/stat/demo.sh
chmod +x /root/demo/stat/demo.sh
cp /bin/echo /root/demo/stat/echo.bin
ln -s /root/demo/stat/note.txt /root/demo/stat/note.lnk

五个对象分别对应普通文本文件、可执行脚本、ELF 二进制、软链接、目录。验证数据就绪:

$ ls -l /root/demo/stat
total 48
-rwxr-xr-x 1 root root    31 Oct 15 06:28 demo.sh
-rwxr-xr-x 1 root root 35128 Oct 15 06:28 echo.bin
lrwxrwxrwx 1 root root    24 Oct 15 06:28 note.lnk -> /root/demo/stat/note.txt
-rw-r--r-- 1 root root    20 Oct 15 06:28 note.txt
drwxr-xr-x 2 root root  4096 Oct 15 06:28 subdir

2.2 --help 全量回显

stat --help 输出全部参数与格式符清单(实测原样保留,可作为格式符速查表):

Usage: stat [OPTION]... FILE...
Display file or file system status.

Mandatory arguments to long options are mandatory for short options too.
  -L, --dereference     follow links
  -f, --file-system     display file system status instead of file status
      --cached=MODE     specify how to use cached attributes;
                          useful on remote file systems. See MODE below
  -c  --format=FORMAT   use the specified FORMAT instead of the default;
                          output a newline after each use of FORMAT
      --printf=FORMAT   like --format, but interpret backslash escapes,
                          and do not output a mandatory trailing newline;
                          if you want a newline, include \n in FORMAT
  -t, --terse           print the information in terse form
      --help     display this help and exit
      --version  output version information and exit

The --cached MODE argument can be; always, never, or default.
`always` will use cached attributes if available, while
`never` will try to synchronize with the latest attributes, and
`default` will leave it up to the underlying file system.

The valid format sequences for files (without --file-system):

  %a   permission bits in octal (note '#' and '0' printf flags)
  %A   permission bits and file type in human readable form
  %b   number of blocks allocated (see %B)
  %B   the size in bytes of each block reported by %b
  %C   SELinux security context string
  %d   device number in decimal
  %D   device number in hex
  %f   raw mode in hex
  %F   file type
  %g   group ID of owner
  %G   group name of owner
  %h   number of hard links
  %i   inode number
  %m   mount point
  %n   file name
  %N   quoted file name with dereference if symbolic link
  %o   optimal I/O transfer size hint
  %s   total size, in bytes
  %t   major device type in hex, for character/block device special files
  %T   minor device type in hex, for character/block device special files
  %u   user ID of owner
  %U   user name of owner
  %w   time of file birth, human-readable; - if unknown
  %W   time of file birth, seconds since Epoch; 0 if unknown
  %x   time of last access, human-readable
  %X   time of last access, seconds since Epoch
  %y   time of last data modification, human-readable
  %Y   time of last data modification, seconds since Epoch
  %z   time of last status change, human-readable
  %Z   time of last status change, seconds since Epoch

Valid format sequences for file systems:

  %a   free blocks available to non-superuser
  %b   total data blocks in file system
  %c   total file nodes in file system
  %d   free file nodes in file system
  %f   free blocks in file system
  %i   file system ID in hex
  %l   maximum length of filenames
  %n   file name
  %s   block size (for faster transfers)
  %S   fundamental block size (for block counts)
  %t   file system type in hex
  %T   file system type in human readable form

--terse is equivalent to the following FORMAT:
    %n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %W %o %C
--terse --file-system is equivalent to the following FORMAT:
    %n %i %l %t %s %S %b %f %a %c %d

NOTE: your shell may have its own version of stat, which usually supersedes
the version described here.  Please refer to your shell's documentation
for details about the options it supports.

GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/stat>
or available locally via: info '(coreutils) stat invocation'

💡 说明:文件与文件系统两套格式符复用同一批字母(如 %a、%b),必须搭配 -f 才切换到文件系统语义,这也是 3.7 节实测的内容。帮助尾部还给出了 --terse 的等价格式,3.8 节据此逐字段解读。

2.3 版本确认

$ stat --version | head -1
stat (GNU coreutils) 8.32

版本确认为 GNU coreutils 8.32,后文所有行为与格式符均以此版本为准。

三、参数逐项实测

本章对 stat 的每个参数逐一实测:先看默认输出怎么读,再依次验证 -L、-c 各组格式符、-f、-t、--printf、--cached,最后看错误路径的退出码。每条命令都给出真实回显与要点解读。

3.1 默认输出:inode 元数据全景与逐行解读

不带任何参数,stat 以人类可读的多行形式展示文件的全部 inode 元数据。以普通文本文件为例:

$ stat /root/demo/stat/note.txt
  File: /root/demo/stat/note.txt
  Size: 20        	Blocks: 8          IO Block: 4096   regular file
Device: 100039h/1048633d	Inode: 31615737    Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-10-15 06:28:08.794414766 +0000
Modify: 2026-10-15 06:28:08.794414766 +0000
Change: 2026-10-15 06:28:08.794414766 +0000
 Birth: 2026-10-15 06:28:08.794414766 +0000

逐行解读:

  • File:文件名。对软链会附加 -> 目标(见 3.2)。
  • Size:文件内容字节数(20 字节)。Blocks:为其分配的 512 字节块数(8 块,即实际占盘 4096 字节——哪怕内容只有 20 字节也至少占一个文件系统块)。IO Block:文件系统 I/O 块大小 4096。行尾 regular file 是文件类型。
  • Device:所在设备号,十六进制 100039h / 十进制 1048633d。Inode:inode 号 31615737。Links:硬链接数 1。
  • Access: (0644/-rw-r--r--):八进制权限与符号权限;Uid/Gid:属主与属组(ID/名称)。
  • Access / Modify / Change / Birth 四个时间戳:分别是最后读取、最后内容修改、最后元数据变更、创建时间,精确到纳秒。三者的差异与实测见 3.4 的技术拓展。

目录、二进制、脚本同构,只是类型与权限不同:

$ stat /root/demo/stat/subdir
  File: /root/demo/stat/subdir
  Size: 4096      	Blocks: 8          IO Block: 4096   directory
Device: 100039h/1048633d	Inode: 31615736    Links: 2
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-10-15 06:28:08.794414766 +0000
Modify: 2026-10-15 06:28:08.794414766 +0000
Change: 2026-10-15 06:28:08.794414766 +0000
 Birth: 2026-10-15 06:28:08.794414766 +0000

$ stat /root/demo/stat/echo.bin
  File: /root/demo/stat/echo.bin
  Size: 35128     	Blocks: 72         IO Block: 4096   regular file
Device: 100039h/1048633d	Inode: 31615739    Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-10-15 06:28:08.805415809 +0000
Modify: 2026-10-15 06:28:08.806415904 +0000
Change: 2026-10-15 06:28:08.806415904 +0000
 Birth: 2026-10-15 06:28:08.805415809 +0000

目录的 Size 恒为 4096(目录项存储块大小),Links 为 2(目录本身加 .);35128 字节的二进制占 72 个 512 字节块。

3.2 -L(--dereference):跟随软链取目标属性

默认 stat 软链时展示链接本身(类型 symbolic link、大小为目标路径字符串长度):

$ stat /root/demo/stat/note.lnk
  File: /root/demo/stat/note.lnk -> /root/demo/stat/note.txt
  Size: 24        	Blocks: 0          IO Block: 4096   symbolic link
Device: 100039h/1048633d	Inode: 31615740    Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-10-15 06:28:08.810416284 +0000
Modify: 2026-10-15 06:28:08.808416094 +0000
Change: 2026-10-15 06:28:08.808416094 +0000
 Birth: 2026-10-15 06:28:08.808416094 +0000

加上 -L 则跟随软链取目标文件的属性——File 行不再带箭头,Size 变成 note.txt 的 20 字节,Inode 与 3.1 中 note.txt 的 31615737 完全一致,类型回到 regular file:

$ stat /root/demo/stat/note.lnk -L
  File: /root/demo/stat/note.lnk
  Size: 20        	Blocks: 8          IO Block: 4096   regular file
Device: 100039h/1048633d	Inode: 31615737    Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-10-15 06:28:08.794414766 +0000
Modify: 2026-10-15 06:28:08.794414766 +0000
Change: 2026-10-15 06:28:08.794414766 +0000
 Birth: 2026-10-15 06:28:08.794414766 +0000

💡 说明:软链自身 Size 是目标路径字符串的字节数(/root/demo/stat/note.txt 共 24 字符),Blocks 为 0——软链内容存进 inode 的"快速符号链接"区,不占数据块。排查"软链指向谁、目标多大"时 -L 一步到位。

3.3 -c(--format)基础属性格式符:%n %s %a %A %h %U %G %i %F

-c 用格式符把默认输出拆成单项值,是脚本里最常用的形态。逐个实测基础属性:

$ stat -c %n /root/demo/stat/note.txt
/root/demo/stat/note.txt
$ stat -c %s /root/demo/stat/note.txt
20
$ stat -c %a /root/demo/stat/note.txt
644
$ stat -c %A /root/demo/stat/note.txt
-rw-r--r--
$ stat -c %h /root/demo/stat/note.txt
1
$ stat -c %U /root/demo/stat/note.txt
root
$ stat -c %G /root/demo/stat/note.txt
root
$ stat -c %i /root/demo/stat/note.txt
31615737
$ stat -c %F /root/demo/stat/note.txt
regular file
  • %n 文件名、%s 字节大小、%i inode 号、%F 类型描述。
  • %a 八进制权限(644)、%A 符号权限(含类型位 -rw-r--r--),小写/大写成对。
  • %h 硬链接数、%U/%G 属主与属组名称(另有 %u/%g 输出数字 ID,见 --help)。

3.4 -c 时间戳格式符:%x %X %y %Y %z %Z %w %W

时间戳格式符分人类可读(小写)与 Unix 秒(大写)两档,另有创建时间 %w/%W:

$ stat -c %x /root/demo/stat/note.txt
2026-10-15 06:28:08.794414766 +0000
$ stat -c %X /root/demo/stat/note.txt
1792045688
$ stat -c %y /root/demo/stat/note.txt
2026-10-15 06:28:08.794414766 +0000
$ stat -c %Y /root/demo/stat/note.txt
1792045688
$ stat -c %z /root/demo/stat/note.txt
2026-10-15 06:28:08.794414766 +0000
$ stat -c %Z /root/demo/stat/note.txt
1792045688
$ stat -c %w /root/demo/stat/note.txt
2026-10-15 06:28:08.794414766 +0000
$ stat -c %W /root/demo/stat/note.txt
1792045688

%x/%X 是 atime,%y/%Y 是 mtime,%z/%Z 是 ctime,%w/%W 是 Birth 创建时间。本环境文件系统记录了创建时间,%w 输出真实时间而非 -、%W 输出真实秒数而非 0;在不记录 crtime 的文件系统上按帮助原文会得到 - 和 0。

💡 技术拓展:Access/Modify/Change/Birth 对应文件系统的四种时间戳,前三种最容易混淆,差异对比如下——

时间戳全称记录什么哪些操作会更新cat 读取是否影响
atimeAccess time最后一次读取内容的时间读类操作(cat、grep 等)、touch -a是,但受 relatime 节流(见下)
mtimeModify time最后一次修改内容的时间写内容(重定向、vim 保存等)、touch -m否
ctimeChange time最后一次变更 inode 元数据的时间chmod、chown、ln 等,且一切更新 atime/mtime 的操作都会连带更新它否(纯读取不触发)

Birth(crtime,创建时间)是第四种,只能被文件系统记录、普通用户态无法直接改写。cat 是否影响 atime 与挂载选项有关:本环境根文件系统以 relatime 方式挂载,仅当 atime 早于 mtime(或超过 24 小时未读)时读操作才回写 atime。下面用 touch -a/touch -m/chmod/cat 实测佐证这张表(ts.txt 为空文件,cat 无输出):

touch /root/demo/stat/ts.txt
$ stat -c 'atime=%x mtime=%y ctime=%z' /root/demo/stat/ts.txt
atime=2026-10-15 06:28:08.901424914 +0000 mtime=2026-10-15 06:28:08.901424914 +0000 ctime=2026-10-15 06:28:08.901424914 +0000

$ touch -a /root/demo/stat/ts.txt

$ stat -c 'atime=%x mtime=%y ctime=%z' /root/demo/stat/ts.txt
atime=2026-10-15 06:28:09.909518939 +0000 mtime=2026-10-15 06:28:08.901424914 +0000 ctime=2026-10-15 06:28:09.909518939 +0000

$ touch -m /root/demo/stat/ts.txt

$ stat -c 'atime=%x mtime=%y ctime=%z' /root/demo/stat/ts.txt
atime=2026-10-15 06:28:09.909518939 +0000 mtime=2026-10-15 06:28:10.915611050 +0000 ctime=2026-10-15 06:28:10.915611050 +0000

$ chmod 600 /root/demo/stat/ts.txt

$ stat -c 'atime=%x mtime=%y ctime=%z' /root/demo/stat/ts.txt
atime=2026-10-15 06:28:09.909518939 +0000 mtime=2026-10-15 06:28:10.915611050 +0000 ctime=2026-10-15 06:28:11.923701643 +0000

三个动作分别验证:touch -a 只动 atime 但连带 ctime 前移(06:28:09.909518939);touch -m 只动 mtime、ctime 同步前移(06:28:10.915611050);chmod 600 只动 ctime(06:28:11.923701643),atime/mtime 纹丝不动。继续验证 cat 与 relatime:先把 atime 故意置早(2026-01-01)、mtime 置晚(2026-06-01),制造"atime 早于 mtime"的回写条件:

$ touch -a -d '2026-01-01 00:00:00' /root/demo/stat/ts.txt

$ touch -m -d '2026-06-01 00:00:00' /root/demo/stat/ts.txt

$ stat -c 'atime=%x mtime=%y ctime=%z' /root/demo/stat/ts.txt
atime=2026-01-01 00:00:00.000000000 +0000 mtime=2026-06-01 00:00:00.000000000 +0000 ctime=2026-10-15 06:28:11.933702540 +0000

$ cat /root/demo/stat/ts.txt

$ stat -c 'atime=%x mtime=%y ctime=%z' /root/demo/stat/ts.txt
atime=2026-10-15 06:28:11.938702989 +0000 mtime=2026-06-01 00:00:00.000000000 +0000 ctime=2026-10-15 06:28:11.933702540 +0000

cat 之后 atime 从 2026-01-01 回写到当前时刻(06:28:11.938702989),mtime 保持 2026-06-01、ctime 保持 06:28:11.933702540 未变——纯读取只影响 atime,不碰 mtime/ctime,与上表结论一致。

3.5 -c 块、设备与链接名格式符:%b %B %d %D %f %N

$ stat -c %b /root/demo/stat/note.txt
8
$ stat -c %B /root/demo/stat/note.txt
512
$ stat -c %d /root/demo/stat/note.txt
1048633
$ stat -c %D /root/demo/stat/note.txt
100039
$ stat -c %f /root/demo/stat/note.txt
81a4
$ stat -c %N /root/demo/stat/note.lnk
'/root/demo/stat/note.lnk' -> '/root/demo/stat/note.txt'
  • %b 分配块数(512 字节块)、%B 单块字节数(512),两者相乘即实际占盘量。
  • %d/%D 设备号十进制/十六进制;%f 原始 mode 的十六进制值(81a4 高位含类型位、低位 1a4 即 0644 权限)。
  • %N 带引号的文件名,对软链自动附加 -> 目标,与默认输出 File 行同源。

3.6 组合格式与多文件输出

-c 的真正威力在自由组合:格式串里可混排格式符与普通文本,一次处理多个文件时每个文件输出一行:

$ stat -c '%n %F %a %U:%G %s bytes' /root/demo/stat/*
/root/demo/stat/demo.sh regular file 755 root:root 31 bytes
/root/demo/stat/echo.bin regular file 755 root:root 35128 bytes
/root/demo/stat/note.lnk symbolic link 777 root:root 24 bytes
/root/demo/stat/note.txt regular file 644 root:root 20 bytes
/root/demo/stat/subdir directory 755 root:root 4096 bytes

再比如用分隔符拼出脚本友好的行:

$ stat -c '%n|inode=%i|size=%s' /root/demo/stat/note.txt /root/demo/stat/echo.bin
/root/demo/stat/note.txt|inode=31615737|size=20
/root/demo/stat/echo.bin|inode=31615739|size=35128

💡 说明:-c 每使用一次 FORMAT 输出后自动换行(帮助原文 output a newline after each use of FORMAT),多文件逐行排列,可直接喂给 sort/awk。

3.7 -f(--file-system):文件系统状态

-f 把查询对象从文件切换到文件所在文件系统:

$ stat -f /root/demo/stat
  File: "/root/demo/stat"
    ID: e6e8891a4f701019 Namelen: 255     Type: overlayfs
Block size: 4096       Fundamental block size: 4096
Blocks: Total: 206014282  Free: 90417896   Available: 81245537
Inodes: Total: 52396032   Free: 46775283

逐项解读:Type 是文件系统类型(本环境为 overlayfs);Block size 是传输优化块大小,Fundamental block size 是统计用基础块大小(本环境同为 4096);Blocks 三列是总块数、空闲块数、普通用户可用块数(按 4096 字节一块换算,Available 约 310 GB);Inodes 是 inode 总量与空闲量,inode 耗尽即使磁盘有空间也无法新建文件,巡检时两项都要看。配合文件系统版格式符取单值:

$ stat -f -c %T /root/demo/stat
overlayfs
$ stat -f -c 'type=%T total=%b free=%f avail=%a inodes total=%c free=%d' /root/demo/stat
type=overlayfs total=206014282 free=90417896 avail=81245537 inodes total=52396032 free=46775283

注意文件系统模式下 %T 是"类型可读名"、%t 是类型的十六进制值,%a/%f/%b/%c/%d 的含义也与文件模式完全不同——同一字母两套语义,务必搭配 -f 使用。

3.8 -t(--terse):简洁单行输出

-t 把全部信息压成单行、以空格分隔,方便脚本按列取值:

$ stat -t /root/demo/stat/note.txt
/root/demo/stat/note.txt 20 8 81a4 0 0 100039 31615737 1 0 0 1792045688 1792045688 1792045688 1792045688 4096

$ stat -t /root/demo/stat/subdir
/root/demo/stat/subdir 4096 8 41ed 0 0 100039 31615736 2 0 0 1792045688 1792045688 1792045688 1792045688 4096

按 --help 尾部给出的等价格式 %n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %W %o %C 对照首行:文件名、20 字节、8 块、mode 81a4、uid 0、gid 0、设备 100039、inode 31615737、硬链接 1、主/次设备类型 0/0(普通文件无设备号)、四个时间戳均为 1792045688、最优 I/O 大小 4096;末尾 %C(SELinux 上下文)本环境未启用故为空。普通文件与目录的差异在第 2 列(4096 为目录大小)和第 9 列硬链接数(2)。

3.9 --printf:可编程的定制输出

--printf 与 -c 类似,但会解释反斜杠转义(\t、\n 等)且不自动补换行,适合精确控制输出形态:

$ stat --printf='%n\t%s bytes\n' /root/demo/stat/note.txt /root/demo/stat/subdir; echo
/root/demo/stat/note.txt	20 bytes
/root/demo/stat/subdir	4096 bytes

格式串里的 \t 生成为制表符、\n 生成为换行——命令尾部的 ; echo 仅为让 shell 提示符回到行首,说明"不自动补换行"这一行为本身。

3.10 --cached:属性缓存控制

--cached=MODE 控制是否使用内核缓存的属性(MODE 取 always/never/default,见 --help 说明),主要面向 NFS 等远程文件系统:

$ stat --cached=always /root/demo/stat/note.txt
  File: /root/demo/stat/note.txt
  Size: 20        	Blocks: 8          IO Block: 4096   regular file
Device: 100039h/1048633d	Inode: 31615737    Links: 2
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-10-15 06:28:08.794414766 +0000
Modify: 2026-10-15 06:28:08.794414766 +0000
Change: 2026-10-15 06:28:11.943703438 +0000
 Birth: 2026-10-15 06:28:08.794414766 +0000

$ stat --cached=never /root/demo/stat/note.txt
  File: /root/demo/stat/note.txt
  Size: 20        	Blocks: 8          IO Block: 4096   regular file
Device: 100039h/1048633d	Inode: 31615737    Links: 2
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-10-15 06:28:08.794414766 +0000
Modify: 2026-10-15 06:28:08.794414766 +0000
Change: 2026-10-15 06:28:11.943703438 +0000
 Birth: 2026-10-15 06:28:08.794414766 +0000

$ stat --cached=default /root/demo/stat/note.txt
  File: /root/demo/stat/note.txt
  Size: 20        	Blocks: 8          IO Block: 4096   regular file
Device: 100039h/1048633d	Inode: 31615737    Links: 2
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-10-15 06:28:08.794414766 +0000
Modify: 2026-10-15 06:28:08.794414766 +0000
Change: 2026-10-15 06:28:11.943703438 +0000
 Birth: 2026-10-15 06:28:08.794414766 +0000

本地文件系统上三种取值输出完全一致(属性本就实时);always 优先用有效缓存、never 强制向文件系统同步最新属性、default 交由底层文件系统决定——差异只在远程文件系统的缓存时效上体现。另注意此处 note.txt 的 Links 已是 2:4.3 节为它创建了硬链接后 ctime 随之更新为 06:28:11.943703438。

3.11 目标不存在:错误信息与退出码

对不存在的路径,stat 向 stderr 报错并以退出码 1 结束:

$ stat /root/demo/stat/nosuch; echo exit=$?
stat: cannot statx '/root/demo/stat/nosuch': No such file or directory
exit=1

错误消息里的 statx 是底层系统调用名。脚本中应先判断退出码或用 test -e 预检,再决定是否取元数据。

四、实战示例

以下示例均可独立执行,组合 stat 的格式符解决常见运维问题;演示数据沿用 /root/demo/stat/ 与系统文件。

4.1 找出目录中最近变动的文件

用 %Y(mtime 的 Unix 秒)配 sort 倒序取前三:

$ stat -c '%Y %n' /root/demo/stat/* | sort -rn | head -3
1792045688 /root/demo/stat/subdir
1792045688 /root/demo/stat/note.txt
1792045688 /root/demo/stat/note.lnk

多数文件创建于同一秒,mtime 并列时按 sort 的稳定顺序排列;ts.txt 曾用 touch -m -d '2026-06-01 00:00:00' 改写 mtime(对应秒值 1780272000),因此排在末尾。把 head -3 换成 tail -3 即"最久未变动"清单。

4.2 核对关键系统文件的属主与权限

安全基线巡检常用一行核对权限与属主:

$ stat -c '%a %U:%G %n' /etc/passwd /etc/shadow
644 root:root /etc/passwd
640 root:shadow /etc/shadow

/etc/shadow 为 640、属组 shadow,符合 Ubuntu 22.04 默认基线;批量巡检时把文件清单传给 xargs stat -c 即可生成核对表。

创建硬链接后,两个名字的 inode 号相同、Links 计数同涨:

$ ln /root/demo/stat/note.txt /root/demo/stat/note-hard.txt

$ stat -c '%n links=%h' /root/demo/stat/note.txt /root/demo/stat/note-hard.txt
/root/demo/stat/note.txt links=2
/root/demo/stat/note-hard.txt links=2

两个文件名 Links 均为 2。再配合 3.3 的 %i 可见两者 inode 号相同(31615737)——这就是"硬链接是同一 inode 的多个名字"的直接证据,也是区分硬链接与复制的关键验证手段。

4.4 用 -f 查看磁盘可用空间

stat -f 不用 df 也能拿到文件系统余量(含 inode 余量):

$ stat -f -c 'type=%T avail_blocks=%a' /root
type=overlayfs avail_blocks=81136978

%a 是普通用户可用块数,乘以基础块大小 4096 即可用字节数;监控脚本里与 3.7 节的完整输出配合,可同时覆盖容量与 inode 两个维度。

4.5 估算文件实际占用磁盘空间

Size 是逻辑大小,占盘量要用 %b 乘 %B:

$ stat -c '%n size=%s blocks=%b x %B bytes' /root/demo/stat/echo.bin
/root/demo/stat/echo.bin size=35128 blocks=72 x 512 bytes

35128 字节的文件实际占 72×512 = 36864 字节——海量小文件场景下,"占盘量远大于内容量"的差距就来自这个最小分配粒度(一个文件系统块 4096 字节起步)。

五、注意事项与常见问题

Q1:文件只有 20 字节,为什么 Blocks 是 8? Blocks 以 512 字节为单位计数(%B=512),文件系统最小按一个块(本环境 4096 字节)分配,20 字节也要占 8 个 512 字节块,见 4.5 的估算示例。

Q2:Access 一词既出现在权限行又出现在时间戳行,怎么区分? Access: (0644/-rw-r--r--) 是权限(与 Uid/Gid 同行),单独成行的 Access: 时间戳 才是 atime;mtime/ctime 只出现在时间戳区,见 3.1 的逐行解读。

Q3:cat 一个文件到底改不改时间戳? 只可能改 atime,且受挂载选项节流:relatime 下仅当 atime 早于 mtime 或超过 24 小时未读才回写;mtime/ctime 纯读取不会变,实测见 3.4 的技术拓展。

Q4:stat 和 ls -l 怎么选? ls -l 面向浏览(多文件、按目录排序),stat 面向单文件全景与脚本取值(含 Birth 时间、纳秒精度时间戳、%n 格式符体系);需要精确字段时一律 -c/--printf。

Q5:Links 字段是什么的计数? 硬链接数——指向同一 inode 的目录项个数。目录至少为 2(自身与 .),普通文件 1;创建/删除硬链接会改变它并连带更新 ctime,见 4.3。

Q6:--cached 什么时候真正有用? 访问 NFS/CIFS 等远程文件系统时,never 强制向服务端同步属性、always 用本地缓存换取性能;本地文件系统三种取值无差别,见 3.10。

Q7:%w 输出 -、%W 输出 0 是坏了吗? 不是。Birth 依赖文件系统记录 crtime,不支持的文件系统按帮助原文返回 - 与 0;本环境实测有真实值(3.4)。

Q8:stat -t 的十几个字段怎么记? 不需要背:--help 尾部给了等价格式 %n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %W %o %C,按位置对照即可,见 3.8 的逐列解读。

六、参考链接