用 ls 按时间排序目录:mtime、atime、ctime 与 btime 实战

直接运行 ls -l 时,文件会按名称字母顺序排列;目录一长,五分钟前刚改过的文件就可能淹没在列表中。本文介绍如何使用 ls -t、-r、-u、-c 和 find,按修改时间、访问时间、变更时间和创建时间正确排序。

查看目录内容,是在任何 Linux 服务器上最先做的事情之一,而 ls 通常是大家顺手使用的命令。不过默认情况下,ls 会按文件名进行字母排序。这对小型主目录没有问题,但当你打开 /etc 或 /var/log,想快速找出最近变更的文件时,这种方式就不太好用了。

在实际系统管理工作中,这种需求非常常见:软件包更新后服务停止运行,你希望查明刚刚改动过哪些配置文件;备份任务每晚执行,脚本需要挑出最新的归档;日志目录里堆着数百个轮转文件,而你只关心当前正在写入的那一个。

ls 可以通过一个选项按时间排序,而且它不只支持最后修改时间,还能按多种不同的时间戳排序。只要弄清每个选项读取的是哪一个时间戳,找出任意目录中最新的或最旧的文件就只需要几秒钟。

Linux 如何记录文件时间戳

在按时间排序之前,先弄清楚 Linux 实际为文件保存哪些时间会很有帮助。ls 的每个排序选项读取的时间戳并不相同,一旦选错,输出顺序看起来就可能毫无规律。

每个文件都会在 inode(磁盘上保存文件元数据的小型记录)中保存以下时间戳:

  • mtime(修改时间):文件内容发生变化时更新。这是 ls -l 默认显示的时间。
  • atime(访问时间):文件被读取时更新;不过大多数系统只会不定期更新,后文会进一步说明。
  • ctime(变更时间):文件元数据发生变化时更新,例如权限、所有者或名称改变;文件内容发生变化时也会更新。它不是创建时间,这一点经常被混淆。
  • btime(创建时间):记录文件创建时刻,前提是文件系统支持,例如 ext4、XFS 和 Btrfs。

要一次查看这四种时间,最简单的方法是使用 stat 命令。下面以 /etc/hosts 为例:

stat /etc/hosts

输出:

  File: /etc/hosts
  Size: 268         Blocks: 8          IO Block: 4096   regular file
Device: 252,1   Inode: 1310834     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-11-02 08:55:10.412367219 +0530
Modify: 2026-10-28 14:03:22.180415667 +0530
Change: 2026-10-28 14:03:22.180415667 +0530
 Birth: 2026-09-14 11:20:47.904112031 +0530

你系统上的大小、inode 编号和设备行会有所不同,因此应重点查看最下面四行时间。如果 Birth 显示为短横线(-),说明该文件所在的文件系统或内核没有提供这个文件的创建时间。

访问时间还需要额外注意。大多数 Linux 发行版默认以 relatime 选项挂载文件系统。这意味着,只有当旧访问时间早于文件的修改时间或变更时间,或者旧访问时间已经超过 24 小时,内核才会更新 atime。这样可以避免每次读取都产生一次磁盘写入,但也意味着同一个下午读取文件两次,并不会让它在访问时间排序中跳到最前面。

读懂 ls -l 输出中的日期和时间列

现在你已经知道存在哪些时间戳,接下来看看 ls 在哪里显示它们,因为后面的每个排序示例都需要正确读取这一列。

-l 选项用于输出长格式列表,其中包括权限、硬链接数、所有者、所属组、大小、修改时间和名称:

ls -l /etc/nginx

输出:

total 68
drwxr-xr-x 2 root root 4096 Feb  9  2026 conf.d
-rw-r--r-- 1 root root 1125 Dec  1  2023 fastcgi.conf
-rw-r--r-- 1 root root 1055 Dec  1  2023 fastcgi_params
-rw-r--r-- 1 root root 2837 Dec  1  2023 koi-utf
-rw-r--r-- 1 root root 2223 Dec  1  2023 koi-win
-rw-r--r-- 1 root root 5465 Dec  1  2023 mime.types
drwxr-xr-x 2 root root 4096 Feb  9  2026 modules-available
drwxr-xr-x 2 root root 4096 Feb  9  2026 modules-enabled
-rw-r--r-- 1 root root 1446 Dec  1  2023 nginx.conf
-rw-r--r-- 1 root root  180 Dec  1  2023 proxy_params
-rw-r--r-- 1 root root  636 Dec  1  2023 scgi_params
drwxr-xr-x 2 root root 4096 Sep 23 12:13 sites-available
drwxr-xr-x 2 root root 4096 Apr 19  2026 sites-enabled
drwxr-xr-x 2 root root 4096 Sep 23 12:13 snippets
-rw-r--r-- 1 root root  664 Dec  1  2023 uwsgi_params
-rw-r--r-- 1 root root 3071 Dec  1  2023 win-utf

注意,有些行显示 12:13 这样的具体时间,另一些行则显示 2026 这样的年份。GNU ls 会为最近六个月内修改过的文件显示时分,对更早的文件改为显示年份。因此,Dec 01 2023 只是说明文件足够旧,所以省略了具体时间。示例 3 会演示如何始终显示完整时间戳。

按时间排序 ls 输出的实用示例

理解时间戳和日期列之后,就可以开始排序了。下面的示例会逐层递进,从日常使用的 ls -lt 一直讲到整个目录树的排序。

示例 1:使用 ls -lt 按修改时间排序

-t 选项指示 ls 按时间排序,最新的文件排在最前面,默认使用修改时间。再配合 -l,这就是查看 /etc 等目录最近有哪些变化的最快方法,特别适合在软件包更新或配置改动导致故障后排查问题。

由于 /etc 中有数百个条目,可以把输出传给 head,只显示前几行:

ls -lt /etc | head -n 6

输出:

total 1092
-rw-r--r--  1 root root    95381 Nov  2 09:12 ld.so.cache
drwxr-xr-x  3 root root     4096 Nov  2 09:11 nginx
drwxr-xr-x  2 root root     4096 Nov  2 09:11 alternatives
-rw-r-----  1 root shadow   1302 Nov  1 18:40 shadow
-rw-r--r--  1 root root     2914 Nov  1 18:40 passwd

第一行 total 表示所列文件占用的磁盘空间,单位为 1K 块。因此 head -n 6 会输出这一行以及最新的五个条目。在这个示例中,可以看到 nginx 目录中的内容在 09:11 发生过变化,而 passwd 和 shadow 在前一天晚上发生了变化,这通常意味着新增或修改了用户账户。

也可以用更易读的长格式选项 --sort=time 写出同样的排序,这种方式适合交给其他人阅读的脚本:

ls -l --sort=time /etc | head -n 6

示例 2:使用 ls -ltr 让最新文件排在最后

第一个示例把最新文件放在顶部,配合 head 很方便;但在包含数百个文件的目录中,输出顶部可能已经滚出屏幕。加上 -r 可以反转顺序,让最新文件排在最下方、紧挨着命令提示符,无需向上滚动就能看到。

这可能是服务器上最常用的命令形式之一,尤其在日志目录中:

ls -ltr /var/log

输出:

...
-rw-r-----  1 syslog adm    184322 Nov  2 08:30 auth.log.1
drwxr-xr-x  2 root   root     4096 Nov  2 09:05 nginx
-rw-r-----  1 syslog adm     48210 Nov  2 09:18 auth.log
-rw-r-----  1 syslog adm    912644 Nov  2 09:20 syslog

最后几行显示的是当前正在写入的文件,排查正在发生的故障时,可以据此判断应该先打开哪个日志。

示例 3:使用 --full-time 显示完整日期和时间

前面已经看到,ls -l 会隐藏较旧文件的具体时分,而且从不显示秒。若两个文件在同一分钟内发生修改,或者需要把文件时间与日志中的时间戳对应起来,这种精度就不够用了。

--full-time 选项会打印完整日期、精确到纳秒的时间以及时区偏移,而且可以与 -t 一起使用:

ls -lt --full-time /etc/nginx

输出:

total 64
-rw-r--r-- 1 root root 1477 2026-11-02 09:11:37.551209183 +0530 nginx.conf
drwxr-xr-x 2 root root 4096 2026-10-28 14:10:02.118540871 +0530 conf.d
drwxr-xr-x 2 root root 4096 2026-10-28 14:10:02.118540871 +0530 sites-available
drwxr-xr-x 2 root root 4096 2026-10-28 14:10:02.118540871 +0530 sites-enabled
-rw-r--r-- 1 root root 1125 2026-04-14 10:02:18.000000000 +0530 fastcgi.conf
-rw-r--r-- 1 root root 1055 2026-04-14 10:02:18.000000000 +0530 fastcgi_params

由软件包安装的文件通常会显示 .000000000,因为软件包只把时间保存到秒。如果完整纳秒时间戳过于冗长,可以用 --time-style 选择更短的格式。例如 long-iso 会输出便于排序的日期和时分,但不包含秒:

ls -lt --time-style=long-iso /etc/nginx

输出:

total 64
-rw-r--r-- 1 root root 1477 2026-11-02 09:11 nginx.conf
drwxr-xr-x 2 root root 4096 2026-10-28 14:10 conf.d

示例 4:按访问时间、变更时间或创建时间排序

到目前为止,每个示例都在按修改时间排序。前面通过 stat 见到的其他时间戳也很有价值,例如你想知道目录中哪些脚本最近确实被执行过,或者哪些文件的权限发生过变化。

可以把以下选项与 -l 和 -t 组合使用:

  • -u:显示访问时间,替代默认的修改时间;同时使用 -t 时会按访问时间排序。单独与 -l 使用时,它只显示访问时间,仍然按名称排序,所以记得加上 -t。
  • -c:以相同方式处理变更时间(ctime)。在执行 chmod 或 chown 但没有改动文件内容之后,这个选项很有用。
  • --time=birth:在文件系统和内核支持的情况下,按创建时间排序并显示该时间。

例如,要查看 /usr/local/bin 中哪些脚本最近被读取过,可以按访问时间排序:

ls -ltu /usr/local/bin

要查找 Web 根目录中最近更改过权限或所有者的文件,可以改为按变更时间排序:

ls -ltc /var/www/html

由于前面介绍的 relatime 行为,访问时间顺序只能作为大致参考,不能视为每次读取的精确记录。

示例 5:在脚本中获取最新的文件或目录

前面的示例主要面向屏幕阅读,但按时间排序在脚本中同样有用。一个常见场景是备份目录:夜间任务会写入新的归档,而另一个脚本只需要复制或验证最新的归档。

由于 -t 会把最新文件排在前面,取输出的第一行就能得到最近的归档:

latest=$(ls -t /srv/backups/*.tar.gz | head -n 1)
echo "Latest backup: $latest"

输出:

Latest backup: /srv/backups/web-2026-11-02.tar.gz

同样的思路也适用于目录。-d 选项让 ls 列出目录本身而不是其内容,*/ 模式又只匹配目录,因此可以查看最近修改过的是哪个项目目录:

ls -ltd /srv/projects/*/

请注意,只有在文件名完全受你控制时才适合解析 ls 输出,例如上面带有日期名称的备份文件。如果文件名中包含换行符,结果就会被破坏,因此下一个示例在无法确定文件名格式时会改用 find。

示例 6:使用 find 跨子目录按时间排序

此前的每个示例都只对单个目录中的文件排序。如果对目录树运行 ls -ltR,ls 仍会分别对各个子目录排序,所以你无法看出整棵树中最后变化的是哪个文件。

这时应使用 find,因为它的 -printf 选项能以可排序格式输出每个文件的修改时间。%T+ 指令会输出 YYYY-MM-DD+HH:MM:SS 格式的时间,按纯文本排序也能得到正确顺序;%p 则输出路径:

sudo find /var/log -type f -printf '%T+ %p\n' | sort -r | head -n 5

输出:

2026-11-02+09:20:14.5521378870 /var/log/syslog
2026-11-02+09:20:14.1189022310 /var/log/journal/8f3c2a.../system.journal
2026-11-02+09:18:41.7703315260 /var/log/auth.log
2026-11-02+09:05:12.3341908870 /var/log/nginx/access.log
2026-11-02+08:30:00.9921045310 /var/log/nginx/error.log

这里使用 sudo,是因为一些日志目录只允许 root 或 adm 组读取;如果不加 sudo,find 会输出 Permission denied 并跳过这些目录。sort -r 把最新文件放到最前面,head -n 5 则只保留整棵目录树中最近的五个文件。

如果你只需要找出最近一段时间内发生变化的文件,而不是完整排序,find /etc -type f -mmin -60 会列出 /etc 下过去 60 分钟内修改过的所有文件。这通常是回答“刚才那次更新到底改了什么”的最快方法。

日常使用 ls 时间排序的技巧

现在你已经可以按任意时间戳排序了。养成几个小习惯,可以让这些命令更快,也能避免一些令人困惑的结果。

如果你每天要输入很多次 ls -ltr,可以在 ~/.bashrc 中添加一个短别名。额外的 -h 选项会用 1.2M 这样的单位显示大小,而不是原始字节数,使列表更容易浏览:

echo "alias lt='ls -ltrh'" >> ~/.bashrc
source ~/.bashrc

比较不同服务器上的时间时,请记住 ls 显示的是服务器本地时区的时间。如果一台服务器使用 UTC,另一台使用 IST,同一时刻可能显示为相差五个半小时。为单条命令设置 TZ 变量,可以按 UTC 显示时间,便于直接比较:

TZ=UTC ls -lt --full-time /etc/nginx

较新的 Ubuntu 版本默认使用 Rust 编写的 uutils coreutils 提供 ls,而 Rocky Linux、AlmaLinux 和 RHEL 使用 GNU coreutils。对于日常排序,本文中的选项在两者上的行为相同,但精确输出空格等细节可能不同。因此在脚本中依赖这些输出之前,应先在自己的系统上核对结果。

最后,如果你刚复制了一个文件,却看到它保留着旧的修改时间,这是正常现象。cp -p、rsync -a 以及解压 tar 等操作会有意保留原始修改时间,因此该文件会按内容最后变更的时间排序,而不是按文件到达服务器的时间排序。它的 ctime 则会显示复制时间,这正是 ls -ltc 能给出答案的另一种场景。

总结

现在,你可以使用 ls -t 配合 -u、-c 或 --time,按修改时间、访问时间、变更时间或创建时间对任意目录列表排序;使用 -r 反转顺序;使用 --full-time 显示精确时间戳。

要查看整棵目录树,可以组合使用 find 的 -printf '%T+ %p\n' 与 sort,一次找出所有子目录中最新变化的文件。

Avatar photo

关于 木子

Email: muzi@vip.rockylinux.cn 微信:VebinLee QQ: 2306867585
Founder of the Rocky Linux Chinese community, MVP、VMware vExpert、TVP, advocate for cloud native technologies, with over ten years of experience in site reliability engineering (SRE) and the DevOps field. Passionate about Cloud Computing、Microservices、CI&CD、DevOps、Kubernetes, currently dedicated to promoting and implementing Rocky Linux in Chinese-speaking regions.
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇