Как мне найти время создания файла?
6 ответов
Есть способ узнать дату создания каталога, просто выполните следующие действия:
Знать индекс каталога по
ls -i
команда (скажем, например, его X)Знайте, в каком разделе ваш каталог сохраняется
df -T /path
команда (скажем, его на/dev/sda1
)Теперь используйте эту команду:
sudo debugfs -R 'stat <X>' /dev/sda1
Вы увидите в выводе:
crtime: 0x4e81cacc:966104fc -- mon Sep 27 14:38:28 2013
crtime - это дата создания вашего файла.
Что я тестировал:
- Создан каталог в определенное время.
- Доступ к нему.
Модифицировал его, создав файл.
Я попробовал команду, и она дала точное время.
- Затем я изменяю его и снова тестирую, время ожидания осталось прежним, но изменилось и время доступа изменилось.
@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
Неспособность stat
чтобы показать время создания из-за ограничения stat(2)
системный вызов, чья структура возврата не содержит поля для времени создания. Начиная с Linux 4.11 (т.е. 17.10 и новее *), однако, новый statx(2)
доступен системный вызов, который включает время создания в свою структуру возврата.
* И, возможно, в старых выпусках LTS, использующих ядра аппаратного стека (HWE). Проверьтеuname -r
чтобы увидеть, используете ли вы ядро по крайней мере в 4.11 для подтверждения.
К сожалению, не просто вызывать системные вызовы напрямую в C-программе. Обычно glibc предоставляет оболочку, которая облегчает работу, но glibc добавляет только оболочку дляstatx(2)
в августе 2018 года (версия 2.28, доступна в 18.10). К счастью, @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, чтобы использовать это (за исключением установки некоторых необходимых пакетов, таких как
make
а такжеlinux-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 вы можете напрямую использоватьstatx
функционировать как описано вman 2 statx
(обратите внимание, что man-страница 18.10 неверна, поскольку glibc еще не добавил обертку).
TL;DR: Просто беги:sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>
(Чтобы выяснить свой фс, запустите df -T /path/to/your/file
скорее всего это будет /dev/sda1
).
Длинная версия:
Мы собираемся запустить две команды:
Узнайте название раздела имя для вашего файла.
df -T /path/to/your/file
Вывод будет выглядеть так (имя раздела первое):
Filesystem Type 1K-blocks Used Available Use% Mounted on /dev/<your fs> ext4 7251432 3481272 3509836 50% /
Узнайте время создания этого файла.
sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>
В выходных ищите
ctime
,
Моя ОС (Ubuntu 20.04, которая поставляется с ядром Linux 5.4.0-28 и GLIBC 2.31) поставлялась только с GNU coreutils 8.30, поэтому мне пришлось заставить ее работать, скомпилировав версию 8.32 GNU coreutils из исходников. Это была относительно безболезненная процедура.
Впоследствии оба
ls
а также
stat
мог работать со временем рождения.
Выход
ls -l --time=birth --time-style=full-iso --no-group
:
Выход
stat
в файловой системе ext4 и файловой системе btrfs:
(Скопировано из моего другого ответа на UNIX и Linux Stack Exchange)
Вам может понадобиться время создания файла в удобочитаемом, но не стандартном формате для использования в конвейере сценария оболочки bash. Например, к префиксу имени файла для соответствующей сортировки в файловом менеджере. Я изменил решение @terdon для этой цели следующим образом.
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 $(date -d "${crtime}" | sed 's/://g'| sed 's/-//g')
done
}
-
date -d ...
анализирует строку даты и времени; -
sed
удаляет специальные символы:
а также-
; - конец строки не добавлен.
Что производит:
get_crtime .bashrc
20201023T181422