stat 命令完全指南
Linux文件元数据的终极探针 | 从inode到时间戳的深度解析
💡 导读:在Linux系统中,每个文件背后都隐藏着丰富的元数据信息——inode号、时间戳、设备号、块大小……stat命令就是揭开这层面纱的利器。它是系统管理员和运维工程师诊断文件问题、编写脚本判断文件状态的必备工具。本文将带你全面掌握stat命令,从基础查看到格式化输出,从文件系统状态到实战脚本应用。
📋 本文目录
一、命令简介 二、基本语法详解 三、核心参数大全 四、文件元数据详解 五、基础实战案例 六、格式化输出精讲 七、文件系统状态查询 八、进阶使用技巧 九、性能优化与注意事项 十、同类命令对比 十一、实战场景演练 十二、总结与速查表
一、命令简介
stat(status)是Linux/Unix系统中用于显示文件或文件系统状态信息的命令行工具。与ls命令不同,ls主要展示文件列表和基本属性,而stat则深入到inode层面,展示文件的完整元数据信息,包括设备号、inode号、硬链接数、权限、所有者、大小、块数以及三种关键时间戳。
stat命令最早出现在Unix系统中,GNU coreutils版本的stat在Linux发行版中广泛使用。它的设计理念非常简洁:直接从文件系统的inode(索引节点)中读取并展示元数据。inode是Unix文件系统的核心概念,每个文件都有一个对应的inode,存储了文件的所有属性信息(除文件名外)。stat命令本质上是调用了stat()系统调用,将内核中inode的数据结构以人类可读的格式呈现出来。
stat命令的核心价值在于:它提供了比ls更详细、更精确的文件信息,并且支持通过格式化字符串自定义输出,使其在Shell脚本中有极高的实用价值。无论是编写监控脚本、文件完整性检查,还是排查文件权限问题,stat都是不可或缺的工具。
与许多Linux命令一样,stat遵循Unix工具的设计哲学——"做一件事并做好"。它不负责修改文件属性(那是chmod、chown的职责),不负责搜索文件(那是find的职责),也不负责计算目录大小(那是du的职责)。stat只专注于一件事:以最精确、最完整的方式展示文件和文件系统的元数据。这种聚焦让stat在其擅长的领域无可替代。
在实际使用中,stat通常不是独立使用的命令,而是作为管道中的一环,将精确提取的文件属性传递给后续命令处理。例如,通过stat -c %s file提取文件大小,再通过awk进行计算,这种组合方式是Shell编程中的常见模式。stat的格式化输出能力使得它比ls | awk这种需要解析文本的方式更加可靠和高效,因为它直接输出结构化数据,不存在格式变化导致解析失败的风险。
在Linux系统中,stat可以显示以下三大类信息:
二、基本语法详解
# 基本语法 stat [OPTION]... FILE...# 查看文件系统状态 stat -f [OPTION]... FILE...# 使用格式化字符串输出 stat -c FORMAT FILE...# 查看多个文件 stat file1.txt file2.txt file3.txt
stat的语法非常直观。OPTION是可选的命令行参数,用于控制输出格式和行为。FILE是目标文件路径,可以指定一个或多个。stat会依次显示每个文件的详细信息。如果不指定文件,stat会尝试从标准输入读取,但这在实际使用中很少见。
stat最强大的特性是格式化输出——通过-c(或--format)参数搭配格式化字符串,你可以精确控制输出哪些字段、以什么顺序输出。这在Shell脚本中尤其有用,因为它让你能轻松提取单个属性值,无需用awk或grep去解析默认输出。
三、核心参数大全
stat命令虽然参数不多,但每个参数都有明确的用途。以下是按功能分类的参数列表:
3.1 基本控制参数
| | |
|---|
| | |
| | |
| | 类似--format,但解释反斜杠转义且不加末尾换行 |
| | |
| | |
3.2 文件格式化序列
这是stat命令最核心的精华所在。通过-c参数搭配以下格式化序列,可以精确提取文件的任意属性:
3.3 文件系统格式化序列
当使用-f参数查看文件系统状态时,可使用以下格式化序列:
四、文件元数据详解
理解stat的输出,首先需要理解Linux文件系统中三种关键时间戳的区别。这是许多初学者容易混淆的地方,但却是运维工作中至关重要的知识点。
| | | |
|---|
| | | |
| | | |
| | inode元数据改变(chmod、chown、重命名等) | |
| | | |
这里有一个关键区别需要特别注意:mtime和ctime的变化时机不同。当你用echo "hello" > file.txt修改文件内容时,mtime和ctime都会更新(因为内容变了,元数据中的大小也变了)。但当你用chmod 755 file.txt修改权限时,只有ctime更新而mtime不变(因为内容没变,但元数据变了)。这个区别在安全审计中非常重要——如果你发现一个配置文件的mtime没变但ctime变了,说明有人修改了文件的权限或所有者,但可能没有改变文件内容。这种隐蔽的篡改方式如果不检查ctime是无法发现的。
另一个重要概念是inode号。每个文件在文件系统中都有一个唯一的inode号,它是文件在存储介质上的真正标识。文件名只是inode的一个别名(目录项)。当两个文件名指向同一个inode时,它们就是硬链接。stat输出的Links字段就是指向该inode的硬链接数量。理解inode对于理解Linux文件系统至关重要:当你"删除"一个文件时,实际上只是删除了目录项(文件名到inode的映射),只有当指向该inode的最后一个硬链接被删除时,inode才会被真正释放,数据块才会被标记为可用。
stat输出中的Device字段也值得理解。它由主设备号和次设备号组成,格式为"十六进制/十进制"。主设备号标识设备驱动程序,次设备号标识同一驱动下的具体设备实例。例如,所有SCSI/SATA硬盘的主设备号通常是8,而不同的分区通过次设备号区分。这个信息在排查存储问题或编写udev规则时非常有用。
五、基础实战案例
案例1:查看文件完整信息
# 查看单个文件的详细信息 stat /etc/passwd# 输出示例:# File: /etc/passwd# Size: 3120 Blocks: 8 IO Block: 4096 regular file# Device: 801h/2049d Inode: 1573123 Links: 1# Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)# Access: 2026-08-03 07:00:00.000000000 +0800# Modify: 2026-07-15 14:30:00.000000000 +0800# Change: 2026-07-15 14:30:00.000000000 +0800# Birth: 2026-07-01 10:00:00.000000000 +0800
案例2:查看多个文件信息
# 同时查看多个文件 stat /etc/hosts /etc/hostname /etc/resolv.conf# 使用通配符查看目录下所有文件 stat /var/log/*.log# 查看目录本身的信息(非目录内容) stat /home/user/
案例3:跟随符号链接
# 默认显示符号链接自身的信息 stat /usr/bin/python# 使用 -L 跟随链接,显示目标文件信息 stat -L /usr/bin/python# 对比:ls -l 也可以看到链接指向 ls -l /usr/bin/python# lrwxrwxrwx 1 root root 9 Jul 1 10:00 /usr/bin/python -> python3
案例4:简洁模式输出
# 简洁模式:所有信息在一行显示 stat -t /etc/passwd# 输出示例:# /etc/passwd 3120 8 81a4 0 0 801 1573123 1 0 0 1722654600 1721020200 1721020200 0 4096# 简洁模式适合在脚本中解析# 字段顺序:name size blocks ... (空格分隔)
案例5:查看文件系统状态
# 查看文件所在文件系统的状态 stat -f /home# 输出示例:# File: "/home"# ID: 8010000000000 Namelen: 255 Type: ext2/ext3# Block size: 4096 Fundamental block size: 4096# Blocks: Total: 5242880 Free: 2621440 Available: 2359296# Inodes: Total: 1310720 Free: 1200000# 简洁模式查看文件系统 stat -t -f /home
六、格式化输出精讲
格式化输出是stat命令的精髓。-c参数允许你使用格式化字符串精确控制输出内容,这在Shell脚本中极为实用。
6.1 提取单个属性
# 只获取文件大小(字节) stat -c %s /var/log/syslog# 只获取inode号 stat -c %i /etc/passwd# 只获取权限的八进制表示 stat -c %a /etc/shadow# 只获取文件类型 stat -c %F /dev/sda1# 输出:block special file# 获取Epoch时间戳(适合脚本计算) stat -c %Y /etc/hosts# 输出:1722654600
6.2 组合多个属性
# 自定义格式:文件名 + 大小 + 权限 + 修改时间 stat -c '%n %s bytes %a %y' /etc/passwd# 输出:/etc/passwd 3120 bytes 644 2026-07-15 14:30:00.000000000 +0800# 类似 ls -l 的自定义输出 stat -c '%A %U %G %s %y %n' /etc/*# 只输出文件名和大小(用制表符分隔) stat -c '%n\t%s' *.log# 批量获取文件创建时间 stat -c '%n: %w' /var/log/*.log
6.3 --printf 的高级用法
--printf与-c的区别在于:--printf会解释反斜杠转义序列(如\n、\t),并且不会在末尾自动添加换行符。这使得--printf适合生成需要精确控制格式的输出:
# 使用 --printf 精确控制输出格式 stat --printf='文件: %n\n大小: %s bytes\n权限: %a\n修改: %y\n' /etc/passwd# 生成CSV格式的文件信息 stat --printf='%n,%s,%a,%U,%G,%y\n' /var/log/*.log# 生成JSON格式(嵌套引号需转义) stat --printf='{"file":"%n","size":%s,"perm":"%a","mtime":"%y"}\n' *.txt七、文件系统状态查询
stat的-f参数可以显示文件系统级别的状态信息,包括总块数、空闲块数、总inode数、空闲inode数等。这些信息与df命令的输出有重叠,但stat提供了更底层的细节。
# 查看根文件系统状态 stat -f /# 格式化输出:总空间、可用空间、文件系统类型 stat -f -c 'Total: %b blocks Free: %f blocks Type: %T' /# 计算磁盘使用百分比(用awk配合) stat -f -c '%b %f' / | awk '{used=$1-$2; printf "%.1f%%\n", used/$1*100}'# 查看inode使用情况 stat -f -c 'Total inodes: %c Free inodes: %d' /# 查看多个挂载点的文件系统类型 stat -f -c '%n: %T' / /home /tmp /var八、进阶使用技巧
技巧1:批量文件大小统计
# 统计目录下所有文件的总大小(仅文件,不含子目录) stat -c %s /var/log/*.log | awk '{sum+=$1} END {print sum" bytes"}'# 按大小排序显示文件 stat -c '%s %n' /var/log/* | sort -rn | head -10# 找出最近7天内修改过的文件 find /etc -type f -exec stat -c '%Y %n' {} \; | \ awk -v cutoff=$(( $(date +%s) - 604800 )) '$1 > cutoff {print $2}'技巧2:文件完整性监控脚本
# 监控关键配置文件的元数据变化#!/bin/bash FILES="/etc/passwd /etc/shadow /etc/sudoers /etc/ssh/sshd_config" BASELINE="/var/log/file_baseline.txt"# 生成基线 stat -c '%i %s %a %Y %Z' $FILES > "$BASELINE"# 定期检查(可加入cron) stat -c '%i %s %a %Y %Z' $FILES | diff "$BASELINE" -# 如果有差异,说明文件被修改过
技巧3:判断文件类型
# 使用 %F 判断文件类型 filetype=$(stat -c %F /dev/sda1) echo "$filetype"# 输出:block special file# 在脚本中根据类型执行不同逻辑 for f in /dev/*; do type=$(stat -c %F "$f") case "$type" in "block special file") echo "块设备: $f" ;; "character special file") echo "字符设备: $f" ;; "symbolic link") echo "符号链接: $f" ;; "directory") echo "目录: $f" ;; esac done
技巧4:权限比较与验证
# 检查文件权限是否为644(安全基线检查) perm=$(stat -c %a /etc/passwd) if [ "$perm" != "644" ]; then echo "警告: /etc/passwd 权限异常: $perm" fi# 批量检查敏感文件权限 for f in /etc/shadow /etc/gshadow /etc/sudoers; do echo "$f: $(stat -c '%a (%A)' $f)" done# /etc/shadow: 640 (-rw-r-----)# /etc/gshadow: 640 (-rw-r-----)# /etc/sudoers: 440 (-r--r-----)
九、性能优化与注意事项
⚡ 性能优化要点:
1. stat每次调用都会发起系统调用,批量查询时避免在循环中逐个调用stat 2. 使用 stat -c 一次性提取多个字段,减少调用次数 3. 对于大量文件,考虑用 find -exec stat 批量处理 4. --printf 比 -c 多了转义处理,性能差异可忽略 5. 在NFS等网络文件系统上,stat可能较慢,因为需要网络往返
⚠️ 易错点提醒:
1. btime(创建时间) 并非所有文件系统都支持,ext4/xfs支持,但较老的ext3可能显示为"-" 2. atime 更新受挂载选项影响:noatime会禁用atime更新,relatime仅在特定条件下更新 3. 对符号链接使用stat默认显示链接自身信息,加 -L 才显示目标文件信息 4. Blocks 字段的单位是512字节(POSIX标准),不是文件系统块大小 5. %s 是逻辑大小,%b*%B 是实际占用磁盘空间,稀疏文件两者差异很大
十、同类命令对比
从对比可以看出,stat在信息深度和格式化能力上都是最强的。当你需要在Shell脚本中精确获取文件的某个属性(如inode号、八进制权限、Epoch时间戳)时,stat是最佳选择。而ls -l适合日常快速浏览,df适合查看磁盘空间,file适合判断文件内容类型。它们各有所长,在实际运维中通常配合使用。
十一、实战场景演练
场景1:日志文件轮转检查
# 检查日志文件是否在预期时间内更新#!/bin/bash LOG_DIR="/var/log" MAX_AGE=86400 # 24小时 = 86400秒 NOW=$(date +%s)# 检查关键日志文件的最后修改时间 for log in /var/log/syslog /var/log/auth.log /var/log/kern.log; do if [ -f "$log" ]; then mtime=$(stat -c %Y "$log") age=$((NOW - mtime)) if [ $age -gt $MAX_AGE ]; then echo "警告: $log 已 $((age/3600)) 小时未更新" else echo "正常: $log 最近更新于 $((age/3600)) 小时前" fi fi done
场景2:安全审计脚本
# 审计SUID/SGID文件的元数据#!/bin/bash# 查找所有SUID文件并显示详细信息 find / -perm /4000 -type f 2>/dev/null | while read f; do stat --printf='文件: %n\n权限: %A\n所有者: %U (%u)\n组: %G (%g)\n大小: %s\n修改: %y\n\n' "$f" done# 检查/etc目录下文件的权限是否符合预期 for f in /etc/passwd /etc/shadow /etc/gshadow /etc/sudoers; do perm=$(stat -c %a "$f") owner=$(stat -c %U "$f") echo "$f -> 权限:$perm 所有者:$owner" done
场景3:磁盘空间监控
# 使用stat -f 监控磁盘空间和inode使用率#!/bin/bash THRESHOLD=80# 检查各挂载点的空间使用率 for mount in / /home /var /tmp; do total=$(stat -f -c %b "$mount") free=$(stat -f -c %f "$mount") used_pct=$(( (total - free) * 100 / total )) if [ $used_pct -gt $THRESHOLD ]; then echo "告警: $mount 使用率 ${used_pct}%" fi# 同时检查inode使用率 total_inode=$(stat -f -c %c "$mount") free_inode=$(stat -f -c %d "$mount") inode_pct=$(( (total_inode - free_inode) * 100 / total_inode )) echo "$mount: 空间 ${used_pct}% | inode ${inode_pct}%" done十二、总结与速查表
stat命令是Linux系统中查看文件元数据的最强工具。它直接从inode中读取信息,提供了比ls更详细、更精确的文件属性。通过强大的格式化输出功能,stat在Shell脚本中有着不可替代的地位——无论是文件完整性监控、安全审计还是磁盘空间检查,stat都能提供精确到字节的元数据支持。
掌握stat的关键在于理解Linux文件系统的inode模型和三种时间戳的区别。当你需要编写自动化运维脚本时,stat的-c格式化输出是你最得力的助手。记住:ls用于浏览,stat用于精确获取——这是Unix工具哲学"做一件事并做好"的完美体现。
📌 常用格式化序列速查
# 文件信息 %n 文件名 %s 文件大小(字节) %i inode号 %F 文件类型 %a 权限(八进制) %A 权限(可读) %U 所有者用户名 %u 所有者UID %G 所属组名 %g 所属组GID %h 硬链接数 %b 已分配块数# 时间戳(可读 / Epoch) %x / %X 访问时间 atime %y / %Y 修改时间 mtime %z / %Z 状态改变时间 ctime %w / %W 创建时间 btime# 文件系统信息(需配合 -f 使用) %b 总数据块数 %f 空闲块数 %a 可用块数(非特权) %c 总inode数 %d 空闲inode数 %T 文件系统类型# 常用参数 -f 显示文件系统状态 -L 跟随符号链接 -c 格式化输出 -t 简洁模式 --printf 格式化(支持转义)
以上就是 stat 命令的完整指南,希望对你有所帮助。
每天一个Linux命令,积少成多,成为Linux高手。
— Linux命令每日一讲 —