Дата полного файла (без утилит GNU)

Вопрос или проблема

Я пытаюсь получить полную дату (создания или изменения) конкретного файла, чтобы передать её другой программе. Я пробовал различные варианты опций с командой ls, но ни одна из них не предоставляет полную дату для файлов младше 6 месяцев, и я ограничен в использовании опций. Когда я пробую определенные опции, я получаю следующее сообщение:

usage: ls [-1ACFHLNRabcdefgilmnopqrstuxEUX] [File...]

Ни одна из них, по моим оценкам, не дает то, что мне нужно, поэтому я попробовал использовать команду stat, но она недоступна для меня.

Я использую оболочку Korn на AIX 5.3, которая имеет ограниченное количество доступных команд. Может кто-то предложить другой способ, которым я мог бы получить дату создания или изменения файла в полном формате (либо dd/mm/yyyy, либо yyyy/mm/dd).

С помощью ls вы, хотя и не всегда сможете получить время, должны сможете получить дату (год, месяц и число).

В локали C вывод даты в ls -l должен быть либо Mmm dd HH:MM для недавних файлов (и вы должны иметь возможность вывести год (либо этот год, либо предыдущий), либо Mmm dd YYYY для старых файлов или файлов с временем изменения в будущем. Таким образом, вы всегда сможете получить дату (YYYY-mm-dd) из этого:

eval "$(date +'year=%Y month=%m')"
LC_ALL=C ls -dln file | awk -v y="$year" -v m="$month" '{
  month = index("--JanFebMarAprMayJunJulAugSepOctNovDec", $6) / 3
  day = $7
  if ($8 ~ /:/)
    year = y - (month > m)
  else
    year = $8
  printf "%04d-%02d-%02d\n", year, month, day
  exit}'

Теперь, если вы хотите получить полное время изменения с максимальной точностью, боюсь, что стандартной команды для этого нет.

Вы найдете некоторые реализации ls, которые имеют опции для этого (ls --full-time с GNU ls или -D <format> с FreeBSD ls например)

Существуют различные и несовместимые реализации команды stat (IRIX, zsh встроенная, GNU, BSD), которые могут вам это предоставить.

Или вы можете использовать предикат -printf из GNU find. Или опцию -r из GNU date.

Не все реализации дадут вам субсекундную гранулярность. И будьте осторожны с часовыми поясами и переходом на летнее/зимнее время, так как в зависимости от выбранного вами формата и часового пояса определенный вывод может быть неоднозначным и относиться к более чем одной возможной дате.

Что касается символических ссылок, вы также можете задать себе вопрос, нужно ли вам время изменения ссылки или её цели. Некоторые из упомянутых здесь опций делают одно или другое по умолчанию, и некоторые из них могут выполнять одну или другую по запросу.

  • zsh stat: stat -F '%Y-%m-%d %T.%N %z' +mtime file
    1992-05-13 14:57:00.123368710 +0100
  • GNU stat: stat -c %y file
    1992-05-13 14:57:00.123368710 +0100
  • BSD stat: stat -t '%F %T %z' -f %Sm file
    1992-05-13 14:57:00 +0100
  • IRIX stat: stat -m file
  • GNU find: find file -prune -printf '%TF %TT %Tz\n'
    1992-05-13 14:57:00.1233687100 +0100
  • GNU date: date -r file '+%F %T.%N %z'
    1992-05-13 14:57:00.123368710 +0100
  • FreeBSD ls: ls -D '[%F %T %z]' -l file
    -r-xr-xr-x 2 bin bin 372298 [1992-05-13 14:57:00 +0100] file
  • GNU ls: ls --full-time -l file
    -r-xr-xr-x 2 bin bin 372298 1992-05-13 14:57:00.123368710 +0100 file
  • ast-open ls: ls -Z '%(mtime:time=%F %T.%N %z)s'
    1992-05-13 14:57:00.123368710 +0100

AIX, которая, судя по вашему синопсису ls, может использовать команду istat (страница man AIX 5.3), которая отображает даты полностью (без субсекундной гранулярности и неоднозначность, если вы не установите TZ на UTC0), хотя и парсить её не так просто:

$ LC_ALL=C TZ=UTC0 istat file
Inode 10360 on device 10/6    File
Protection: r-xr-xr-x
Owner: 2(bin)     Group: 2(bin)
Link count: 2     Length 372298 bytes

Last updated:  Wed May 13 14:08:13 1992
Last modified: Wed May 13 13:57:00 1992
Last accessed: Sun Jan 31 15:49:23 1993

Также обратите внимание, что для символических ссылок вы получите дату цели символической ссылки, а не самой ссылки.

Если у вас нет доступа ни к одной из этих команд, ваша наилучшая ставка для портативности может быть perl:

$ perl -MPOSIX -le 'print strftime("%Y-%m-%d %T %z", localtime((lstat(shift))[9]))' file
1992-05-13 14:57:00 +0100

Обратите внимание, что у немногих систем есть время создания для файлов (иногда называемое временем рождения), и нет стандартного API, не говоря уже о команде для его запроса, так что ситуация еще хуже, чем с временем изменения.

Вот функция POSIX для этого:

mtime() {
   touch -r "$1" /tmp/mtime.$$
   diff -u /tmp/mtime.$$ /dev/null | head -n 1 | cut -f 2
   rm -f /tmp/mtime.$$
}

Это создает временный файл ($$ — это текущий идентификатор процесса) с временем изменения указанного файла (необходимым для обработки не текстовых данных, так как POSIX diff лишен --text/-a), и генерирует объединённый diff по сравнению с пустым файлом. head гарантирует, что мы смотрим только на первую строку этого diff, а cut извлекает метку времени. Затем удаляем временный файл.

Результат:

$ mtime ~/.profile
2019-07-01 06:25:34.000000000 -0500

Если у вас есть GNU ls:

ls --time-style=long-iso -l

или

ls --time-style=+FMT -l

где FMT следует за форматом команды date. В вашем случае:

ls --time-style=+%Y/%m/%d -l

Ответ или решение

Чтобы получить полную дату (создания или изменения) конкретного файла на системе AIX 5.3 с использованием оболочки Korn и без GNU утилит, вы можете применять несколько методов, даже при ограниченности доступных команд, которые, как вы указали, возникает из-за особенностей вашей системы.

Метод 1: Использование ls

Вы можете использовать команду ls с различными опциями для получения даты изменения файла, несмотря на то, что полное время может не отображаться. Параметры команды ls могут указывать на дату изменения в формате:

  • Для файлов, измененных в течение последних 6 месяцев, вывод будет с указанием времени: Mmm dd HH:MM
  • Для старых файлов (более 6 месяцев): Mmm dd YYYY

Пример команды:

LC_ALL=C ls -dln файл | awk '{
  month = index("--JanFebMarAprMayJunJulAugSepOctNovDec", $6) / 3
  day = $7
  if ($8 ~ /:/) {
    year = strftime("%Y") - (month > strftime("%m"))
  } else {
    year = $8
  }
  printf "%04d-%02d-%02d\n", year, month, day
  exit
}'

Метод 2: Использование istat

В AIX доступна команда istat, которая позволяет получить более детальную информацию о файле, включая полные даты его модификации и доступа. Хотя вывод istat не всегда легко парсить, он способен предоставить вам необходимую дату.

Пример команды:

LC_ALL=C TZ=UTC0 istat файл

Вывод может выглядеть следующим образом:

Last updated:  Wed May 13 14:08:13 1992
Last modified: Wed May 13 13:57:00 1992
Last accessed: Sun Jan 31 15:49:23 1993

Метод 3: Использование Perl

Если у вас есть возможность использовать Perl, вы можете извлечь дату модификации файла с высокой точностью. В этом случае вам нужно будет использовать встроенные функции для работы с временем.

Пример команды:

perl -MPOSIX -le 'print strftime("%Y-%m-%d %T %z", localtime((lstat(shift))[9]))' файл

Вывод будет в формате YYYY-MM-DD HH:MM:SS, который легко интерпретировать.

Метод 4: Оптимизированная функция mtime

Вы также можете использовать пользовательскую функцию mtime, чтобы получить дату модификации файла без его изменения. Вот пример такой функции:

mtime() {
   touch -r "$1" /tmp/mtime.$$
   diff -u /tmp/mtime.$$ /dev/null | head -n 1 | cut -f 2
   rm -f /tmp/mtime.$$
}

Заключение

Выбор метода зависит от того, какие команды доступны в вашей системе и насколько удобен каждый из подходов. Если stat отсутствует, istat и персональные скрипты с использованием Perl могут быть надежными решениями. Несмотря на ограничения AIX 5.3, указанные методы помогут вам получить необходимую информацию о файлах.

Готовы получить дополнительную помощь? Не стесняйтесь задавать вопросы или уточнять информацию!

Оцените материал
Добавить комментарий

Капча загружается...