Вопрос или проблема
Мне нужно узнать время создания файла. Когда я читал статьи по этой теме, все утверждали, что решения нет (например, Site1, Site2).
Когда я попробовал команду stat
, она выдала Birth: -
.
Как же я могу узнать время создания файла?
Существует способ узнать дату создания каталога, просто следуйте этим шагам:
-
Узнайте inode каталога с помощью команды
ls -i
(пусть это будет X) -
Узнайте, на каком разделе сохранен ваш каталог с помощью команды
df -T /path
(предположим, это/dev/sda1
) -
Теперь используйте эту команду:
sudo debugfs -R 'stat <X>' /dev/sda1
Вы увидите в выводе:
crtime: 0x4e81cacc:966104fc -- пн сен 27 14:38:28 2013
crtime — это дата создания вашего файла.
Что я тестировал:
- Создал каталог в определенное время.
- Получил доступ к нему.
-
Изменил его, создав файл.
-
Я попробовал команду, и она дала точное время.
- Затем я изменил его и протестировал снова, crtime остался тем же, но modify и access время изменились.
@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 Ср мая 21 17:11:08 2014
foo/file Ср мая 21 17:11:27 2014
Невозможность stat
показать время создания связана с ограничением системного вызова stat(2)
, структура возврата которого не включает поле для времени создания. Однако начиная с Linux 4.11 (т.е. 17.10 и новее*), доступен новый системный вызов statx(2)
, который включает время создания в своей структуре возврата.
* И, возможно, на более старых LTS выпусках с использованием ядер stack аппаратного обеспечения (HWE). Проверьте uname -r
, чтобы увидеть, используете ли вы ядро хотя бы 4.11 для подтверждения.
К сожалению, не так просто напрямую вызывать системные вызовы в программе C. Обычно glibc предоставляет обертку, которая упрощает задачу, но glibc добавила обертку для statx(2)
только в августе 2018 года (версия 2.28, доступная в 18.10). Команда stat
сама получила поддержку statx(2)
только в GNU coreutils 8.31 (выпущена в марте 2019), однако, даже Ubuntu 20.04 имеет только coreutils 8.30.
Но я не думаю, что это будет перенесено на LTS выпуски, даже если они получат, или уже имеют, более новые ядра или glibc. Поэтому я не ожидаю, что stat
на любом текущем LTS выпуске (16.04, 18.04 или 20.04) когда-либо распечатает время создания без ручного вмешательства.
На 18.10 и новее вы можете напрямую использовать функцию statx
, как описано в man 2 statx
(обратите внимание, что страница man 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 позже <https://gnu.org/licenses/gpl.html>.
Это свободное программное обеспечение: вы можете изменять и распространять его.
Гарантий НЕТ, в той мере, в какой это допускается законом.
Написано Майклом Мескесом.
# stat /
Файл: /
Размер: 4096 Блоки: 8 IO Блок: 4096 каталог
Устройство: 88h/136d Inode: 57279593 Ссылки: 1
Доступ: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Доступ: 2020-08-18 06:57:46.912243164 +0000
Изменено: 2020-08-18 06:57:06.768492334 +0000
Изменено: 2020-08-18 06:57:59.136165661 +0000
Время создания: 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>
// пока не предоставляет обертку для системного вызова statx()
#include <sys/syscall.h>
/* этот код работает только с x86 и 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 @{}
Пн ноя 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
$ # некоторое время спустя
$ echo > foo/bar
$ chmod og-w foo/bar
$ ./birth foo/bar | xargs -I {} date -d @{}
Пн ноя 27 14:43:21 UTC 2017
$ stat foo/bar
Файл: foo/bar
Размер: 1 Блоки: 8 IO Блок: 4096 обычный файл
Устройство: 700h/1792d Inode: 99 Ссылки: 1
Доступ: (0644/-rw-r--r--) Uid: ( 1000/ muru) Gid: ( 1000/ muru)
Доступ: 2017-11-27 14:43:32.845579010 +0000
Изменено: 2017-11-27 14:44:38.809696644 +0000
Изменено: 2017-11-27 14:44:45.536112317 +0000
Время создания: -
Тем не менее, это не сработало для NTFS и exfat. Я предполагаю, что файловые системы FUSE для них не включали время создания.
Вкратце:
Просто выполните:
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
Вывод будет выглядеть примерно так (имя раздела первое):
Файловая система Тип 1K-блоки Использовано Доступно Использовано% Смонтировано на /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
stat filenameuwantcreationdateof.xxx |grep Birth|cut -d' ' -f 3,4|cut -d. -f 1
это однострочный код, где вы:
запускаете команду stat на обсуждаемом файле, а затем передаете это в |
grep, чтобы вы видели только строку, которая говорит “Birth”, а затем передаете это в |
команду cut с пробелом в качестве разделителя и смотрите на 3-е и 4-е поля, а затем передаете это в |
второй cut с точкой в качестве разделителя и ищете первое поле, чтобы отрезать остаток секунд.
Завершение этого в виде сценария оболочки оставлено как упражнение для пользователя. 8)
2$ stat /tmp/shmem_fpga_reader_writer_tester.log
Файл: /tmp/shmem_fpga_reader_writer_tester.log
Размер: 3000203 Блоки: 5872 IO Блок: 4096 обычный файл
Устройство: 820h/2080d Inode: 2364 Ссылки: 1
Доступ: (0644/-rw-r--r--) Uid: ( 1000/ jleslie) Gid: ( 1000/ jleslie)
Доступ: 2024-11-25 20:02:52.385904749 -0500
Изменено: 2024-11-25 20:11:23.009210519 -0500
Изменено: 2024-11-25 20:11:23.009210519 -0500
Время создания: 2024-11-21 13:58:38.142518388 -0500
2$ stat /tmp/shmem_fpga_reader_writer_tester.log |grep Birth|cut -d' ' -f 3,4|cut -d. -f 1
2024-11-21 13:58:38
2$
Ответ или решение
Чтобы узнать время создания файла в Linux, существуют несколько способов, однако важно помнить, что доступные методы могут зависеть от используемой файловой системы и версии ядра. Рассмотрим их более детально.
Понимание ограничения команды stat
Команда stat
предоставляет информацию о файлах, включая время доступа, изменения и модификации. Однако, в некоторых системах (особенно до версии ядра 4.11) поле Birth
(время создания) может отсутствовать, что приводит к выводу Birth: -
. Это связано с ограничениями системного вызова stat(2)
. В версии ядра 4.11 и выше добавлен новый системный вызов statx(2)
, который включает в себя поле для времени создания.
Проверка версии ядра и поддержка statx
Для начала, проверьте версию вашего ядра с помощью команды:
uname -r
Если ваша версия ядра 4.11 или выше, вы можете использовать команды, которые поддерживают statx
. Если ваша версия ниже, вам, возможно, придется использовать альтернативные методы, такие как debugfs
.
Метод с использованием debugfs
Если вы используете файловую систему ext2, ext3 или ext4, вы можете использовать команду debugfs
для получения информации о времени создания. Вот пошаговое руководство:
-
Узнайте инод файла с помощью команды
ls -i
:ls -i /путь/к/вашему/файлу
-
Узнайте, на каком разделе находится файл с помощью команды
df -T
:df -T /путь/к/вашему/файлу
-
Используйте
debugfs
, чтобы получить время создания:sudo debugfs -R 'stat <инод>' /dev/<имя_раздела>
В выводе ищите строку
crtime
, которая указывает время создания.
Скрипт для автоматизации
Для удобства, можно создать скрипт get_crtime
, который объединит вышеперечисленные шаги:
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
}
После добавления этого скрипта в ваш ~/.bashrc
, вы сможете вызывать его просто командой get_crtime
.
Использование команды stat
в новых системах
В системах с ядром 4.11 и новее, достаточно вызвать команду stat
для получения информации о времени создания:
stat filename
Вывод покажет время создания, если файловая система и версия ядра это поддерживают.
Общие замечания
- Файловые системы: Обратите внимание, что не все файловые системы (например, NTFS или exFAT) поддерживают возможность получения времени создания через
debugfs
. - Права доступа: Для использования
debugfs
может потребоваться доступ суперпользователя. - Версии утилит: Убедитесь, что версии команд
coreutils
иglibc
соответствуют необходимым требованиям для поддержки новых функций.
Заключение
Определение времени создания файла в Linux может быть не всегда простым, особенно в зависимости от конфигураций системы. Однако, с использованием подходящих инструментов и команд, можно получить необходимую информацию. Оперируя полученными данными, вы сможете эффективно управлять файлами и устройствами на системе Linux.