Вопрос или проблема
Я пытаюсь получить полную дату (создания или изменения) конкретного файла, чтобы передать её другой программе. Я пробовал различные варианты опций с командой 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, указанные методы помогут вам получить необходимую информацию о файлах.
Готовы получить дополнительную помощь? Не стесняйтесь задавать вопросы или уточнять информацию!