如何找到文件的创建时间?

如何找到文件的创建时间?

我需要找到一个文件的创建时间,当我阅读一些关于这个问题的文章时,都提到没有解决方案(比如站点1站点2)。

当我尝试该stat命令时,它显示 Birth: -

那么如何才能找到文件的创建时间?

答案1

有一种方法可以知道目录的创建日期,只需按照以下步骤操作:

  1. 了解索引节点通过命令访问目录ls -i(比如说X

  2. 通过命令了解目录保存在哪个分区上df -T /path(假设它在 /dev/sda1

  3. 现在使用此命令:sudo debugfs -R 'stat <X>' /dev/sda1

您将在输出中看到:

crtime: 0x4e81cacc:966104fc -- mon Sep 27 14:38:28 2013

crtime 是您的文件的创建日期。

我测试了什么

  1. 在特定时间创建目录。
  2. 已访问。
  3. 通过创建文件来修改它。

  4. 我尝试了该命令并给出了准确的时间。

  5. 然后我修改它,并再次测试,crtime保持不变,但调整使用权時間變化了。

答案2

@Nux 找到了一个很好的解决方案对此,你们都应该点赞。我决定写一个小函数,可以用来直接运行一切。只需将其添加到您的 ~/.bashrc.

get_crtime() {

    for target in "${@}"; do
        inode=$(stat -c '%i' "${target}")
        fs=$(df  --output=source "${target}"  | tail -1)
        crtime=$(sudo debugfs -R 'stat <'"${inode}"'>' "${fs}" 2>/dev/null | 
        grep -oP 'crtime.*--\s*\K.*')
        printf "%s\t%s\n" "${target}" "${crtime}"
    done
}

现在,您可以运行get_crtime来打印任意数量的文件或目录的创建日期:

$ get_crtime foo foo/file 
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014

答案3

无法stat显示创作时间是由于stat(2)系统调用,其返回结构不包含创建时间字段。但是从 Linux 4.11(即 17.10 及更高版本*)开始,新的statx(2)系统调用可用,其返回结构中包含创建时间。

* 可能在较旧的 LTS 版本上使用硬件支持堆栈 (HWE) 内核。请检查uname -r您是否正在使用至少 4.11 版本的内核以进行确认。

不幸的是,在 C 程序中直接调用系统调用并不容易。通常,glibc 会提供一个包装器来简化这项工作,但 glibc 仅statx(2)在 2018 年 8 月添加了包装器(版本2.28,在 18.10 中可用)。该命令本身仅在 GNU coreutils 中stat获得支持statx(2)8.31(2019 年 3 月发布)然而,即使Ubuntu 20.04 仅具有 coreutils 8.30

但我不认为这将被移植到 LTS 版本,即使它们确实获得了或已经使用了较新的内核或 glibc。因此,我并不stat期望任何当前 LTS 版本(16.04、18.04 或 20.04)无需人工干预即可打印创建时间。

在 18.10 及更高版本中,您可以直接使用statx如下函数man 2 statx(请注意,18.10 手册页错误地指出 glibc 尚未添加包装器)。

在 Ubuntu 20.10 中,您将能够stat直接使用:

# stat --version
stat (GNU coreutils) 8.32
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Michael Meskes.
# stat /
  File: /
  Size: 4096        Blocks: 8          IO Block: 4096   directory
Device: 88h/136d    Inode: 57279593    Links: 1
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-08-18 06:57:46.912243164 +0000
Modify: 2020-08-18 06:57:06.768492334 +0000
Change: 2020-08-18 06:57:59.136165661 +0000
 Birth: 2020-08-18 06:57:06.768492334 +0000

对于较旧的系统,幸运的是,@whotwagner 写道示例 C 程序显示了如何statx(2)在 x86 和 x86-64 系统上使用系统调用。其输出格式与stat默认格式相同,没有任何格式化选项,但可以简单地对其进行修改以仅打印出生时间。

首先,克隆它:

git clone https://github.com/whotwagner/statx-fun

您可以编译statx.c代码,或者,如果您只想要出生时间,请使用birth.c以下代码在克隆的目录中创建(这是statx.c仅打印包括纳秒精度的创建时间戳的最小版本):

#define _GNU_SOURCE
#define _ATFILE_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include "statx.h"
#include <time.h>
#include <getopt.h>
#include <string.h>

// does not (yet) provide a wrapper for the statx() system call
#include <sys/syscall.h>

/* this code works ony with x86 and x86_64 */
#if __x86_64__
#define __NR_statx 332
#else
#define __NR_statx 383
#endif

#define statx(a,b,c,d,e) syscall(__NR_statx,(a),(b),(c),(d),(e))

int main(int argc, char *argv[])
{
    int dirfd = AT_FDCWD;
    int flags = AT_SYMLINK_NOFOLLOW;
    unsigned int mask = STATX_ALL;
    struct statx stxbuf;
    long ret = 0;

    int opt = 0;

    while(( opt = getopt(argc, argv, "alfd")) != -1)
    {
        switch(opt) {
            case 'a':
                flags |= AT_NO_AUTOMOUNT;
                break;
            case 'l':
                flags &= ~AT_SYMLINK_NOFOLLOW;
                break;
            case 'f':
                flags &= ~AT_STATX_SYNC_TYPE;
                flags |= AT_STATX_FORCE_SYNC;
                break;
            case 'd':
                flags &= ~AT_STATX_SYNC_TYPE;
                flags |= AT_STATX_DONT_SYNC;
                break;
            default:
                exit(EXIT_SUCCESS);
                break;
        }
    }

    if (optind >= argc) {
        exit(EXIT_FAILURE);
    }

    for (; optind < argc; optind++) {
        memset(&stxbuf, 0xbf, sizeof(stxbuf));
        ret = statx(dirfd, argv[optind], flags, mask, &stxbuf);
        if( ret < 0)
        {
            perror("statx");
            return EXIT_FAILURE;
        }
        printf("%lld.%u\n", *&stxbuf.stx_btime.tv_sec, *&stxbuf.stx_btime.tv_nsec);
    }
    return EXIT_SUCCESS;
}

然后:

$ make birth
$ ./birth ./birth.c
1511793291.254337149
$ ./birth ./birth.c | xargs -I {} date -d @{}
Mon Nov 27 14:34:51 UTC 2017

从理论上来说,这应该使得创建时间更容易获得:

  • 应该支持更多的文件系统,而不仅仅是 ext* 文件系统(debugfs这是一个适用于 ext2/3/4 文件系统的工具,在其他文件系统上无法使用)
  • 您不需要 root 权限才能使用此功能(除了安装一些所需的软件包,如makelinux-libc-dev)。

测试 xfs 系统,例如:

$ truncate -s 1G temp; mkfs -t xfs temp; mkdir foo; sudo mount temp foo; sudo chown $USER foo
$ touch foo/bar
$ # some time later
$ echo > foo/bar
$ chmod og-w foo/bar
$ ./birth foo/bar | xargs -I {} date -d @{}
Mon Nov 27 14:43:21 UTC 2017
$ stat foo/bar                             
  File: foo/bar
  Size: 1           Blocks: 8          IO Block: 4096   regular file
Device: 700h/1792d  Inode: 99          Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/ muru)      Gid: ( 1000/ muru)
Access: 2017-11-27 14:43:32.845579010 +0000
Modify: 2017-11-27 14:44:38.809696644 +0000
Change: 2017-11-27 14:44:45.536112317 +0000
 Birth: -

但是,这不适用于 NTFS 和 exfat。我猜这些文件系统的 FUSE 文件系统不包括创建时间。

答案4

我的操作系统(Ubuntu 20.04,带有 Linux 内核 5.4.0-28 和 GLIBC 2.31)只附带 GNU coreutils 8.30,所以我必须通过从源代码编译 GNU coreutils 8.32 版本。这是一个相对无痛的手术。

此后,ls和都stat可以与出生时间一起工作。

输出ls -l --time=birth --time-style=full-iso --no-groupls 出生时间

statext4 文件系统和 btrfs 文件系统上 的输出:出生时间统计

(摘自我在 UNIX & Linux Stack Exchange 上的另一个回答

相关内容