当前位置: 首页>>技术教程>>正文


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

, , ,

问题描述

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

当我尝试使用stat命令时,它指出Birth: -

那我怎样才能找到文件的创建时间?

最佳解决办法

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

  1. 通过ls -i命令知道目录的inode(比如说它的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保持不变,但修改和访问时间改变了。

次佳解决办法

@Nux找到了a great solution,你应该全部投票。我决定编写一个可用于直接运行所有内容的小函数。只需将其添加到您的~/.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

第三种解决办法

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

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

不幸的是,直接在C程序中调用系统调用并不容易。通常,glibc提供了一个使工作变得简单的包装器,但glibc仅在2018年8月为statx(2)添加了一个包装器(版本为2.28,可在18.10中获得)。幸运的是,@ wwwwner写了a sample C program,它展示了如何在x86和x86-64系统上使用statx(2)系统调用。它的输出格式与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文件系统不包括创建时间。


如果,或者更确切地说,当glibc添加对statx(2)系统调用的支持时,stat将很快跟进,我们将能够使用普通的旧stat命令。但是我不认为这会被反向移植到LTS版本,即使它们确实获得了更新的内核。因此,我不希望stat在任何当前的LTS版本(14.04,16.04或18.04)上打印创建时间而无需人工干预。

但是,在18.10中,您可以直接使用stat 2函数,如man 2 statx中所述(请注意,18.10联机帮助页在说明glibc尚未添加包装器时不正确)。

第四种办法

长话短说:刚刚运行:sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>

(要计算你的fs,运行df -T /path/to/your/file,很可能它将是/dev/sda1)。

长版:

我们将运行两个命令:

  1. 找出文件的分区名称。

    df -T /path/to/your/file
    

    输出看起来像这样(分区名称是第一个):

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. 找出该文件的创建时间。

    sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>
    

    在输出中,查找ctime

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/1713.html,未经允许,请勿转载。