У меня есть файл, который содержит даты эпох, которые мне нужно преобразовать в удобочитаемые человеком. Я уже знаю, как сделать преобразование даты, например:
[server01 ~]$ date -d@1472200700
Fri 26 Aug 09:38:20 BST 2016
... но я изо всех сил пытаюсь выяснить, как sed
пройтись по файлу и преобразовать все записи. Формат файла выглядит следующим образом:
#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web
text-processing
sed
date
машинист
источник
источник
HISTTIMEFORMAT
переменную оболочки, чтобы контролировать формат во время записи.date -d
не является переносимым, чтобы сказать, Solaris ... Я предполагаю, что это в системе, в основном с инструментами GNU? (GNU AWK / Perl, как правило, являются более переносимыми методами для преобразования дат).gawk '{ if ($0 ~ /^#[0-9]*$/) {print strftime("%c",substr($0,2)); } else {print} }' < file
(strftime
кажетсяОтветы:
Предполагая согласованный формат файла,
bash
вы можете прочитать файл построчно, проверить, находится ли он в заданном формате, а затем выполнить преобразование:BASH_REMATCH
является массивом, первый элемент которого является первой захваченной группой в сопоставлении Regex=~
, в данном случае эпохой.Если вы хотите сохранить структуру файла:
это выведет измененное содержимое в STDOUT, чтобы сохранить его в файле, например
out.txt
:Теперь, если вы хотите, вы можете заменить оригинальный файл:
Пример:
источник
bash
,printf
может сделать сам преобразование:printf '#%(%F %H)T\n' "${BASH_REMATCH[1]}"
.Хотя это возможно с GNU
sed
с такими вещами, как:Это было бы ужасно неэффективно (и легко ввести произвольные уязвимости внедрения команд 1 ), поскольку это означало бы запуск одной оболочки и одной
date
команды для каждой#xxxx
строки, практически так же плохо, какwhile read
цикл оболочки . Здесь было бы лучше использовать такие вещи, какperl
илиgawk
, то есть утилиты обработки текста, которые имеют встроенные возможности преобразования даты:Или:
1 Если бы мы написали
^#([0-9]).*
вместо^#([0-9]).*$
(как я делал в более ранней версии этого ответа), то в многобайтовых локалях, таких как UTF-8 (в настоящее время это норма), с вводом наподобие#1472047795<0x80>;reboot
, где это<0x80>
значение байта 0x80, которое не формирует допустимый символ, например, этаs
команда должна была бы выполнятьсяdate -d@1472047795<0x80>; reboot
. Хотя с дополнительным$
, эти строки не будут заменены. Альтернативный подход:s/^#([0-9])/date -d @\1 #/e
оставить часть после#xxx
даты в виде комментария оболочкиисточник
date -f
для выполнения всех преобразований в потоковом режиме?s
флага делает так, что.*
также включает перевод строки при вводе. Вы также можете использоватьstrftime "%c", localtime $1
.Все остальные ответы порождают новый
date
процесс для каждой даты эпохи, которую необходимо преобразовать. Это может потенциально увеличить производительность, если ваш ввод велик.Однако в GNU date есть удобная
-f
опция, которая позволяет одному экземпляру процессаdate
непрерывно читать входные даты без необходимости нового форка. Таким образом, мы можем использоватьsed
,paste
иdate
таким образом, чтобы каждый из них появлялся только один раз (2 раза заsed
) независимо от того, насколько велик вход:sed
команды, соответственно, в основном удаляют четные и нечетные строки ввода; первый также заменяется#
на,@
чтобы дать правильный формат метки времени эпохи.sed
выводится первый вывод,date -f
который выполняет необходимое преобразование даты для каждой полученной строки ввода.paste
. Эти<( )
конструкции являются Баш процесс замены , которые эффективно Trick Пасты, думая , что читает из заданных имен файлов , когда это на самом деле читает вывод поступает из команды изнутри.-d '\n'
говоритpaste
разделить нечетные и четные выходные строки новой строкой. Вы можете изменить (или удалить) это, если, например, вы хотите, чтобы отметка времени находилась в той же строке, что и другой текст.Обратите внимание, что в этой команде есть несколько GNUisms и Bashisms. Это не является Posix-совместимым и не должно быть переносимым за пределами мира GNU / Linux. Например,
date -f
делает что-то еще на OSXesdate
вариант BSD .источник
date -d
(из вопроса) также непереносим ... (На FreeBSD он попытается связываться с настройками DST, на Solaris это выдаст ошибку ...) Хотя вопрос не определяет ОС ...Предполагая, что формат даты, который вы используете в своем сообщении, соответствует вашему желанию, следующее регулярное выражение должно соответствовать вашим потребностям.
Помните о том, что это заменит только одну эпоху на строку.
источник
sed: -e expression #1, char 48: invalid reference \3 on 's' command's RHS
используя sed:
вывод :
так как мой язык локали арабский :)
источник
Мое решение, как это сделать в конвейере
источник