В настоящее время я пишу сценарий для архивирования пары файлов журнала и хочу, чтобы они были объединены в один архив, который назван в соответствии с датой и временем первой и последней строк в одном из файлов журнала (то есть access.log).
Но для лучшего из себя я не могу обернуться, как получить эту информацию из строк и собрать ее в имя файла.
рассматриваемые строки взяты из файла apache.log, который я просто мог получить с помощью head
и tail
:
Пример:
$ head -n1 /home/server/log/access.log.1
84.1.11.243 - - [21/Jan/2017:14:53:49 +0000] "GET /index.php/2016/05/26/tutorial-how-to-install-ubuntu-and-other-debian-based-distributions-via-debootstrap/ HTTP/1.1" 200 18413 "https://www.google.hu/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"
$ tail -n1 /home/server/log/access.log.1
71.3.17.120 - - [20/Dec/2017:16:17:50 +0000] "POST / HTTP/1.1" 200 27639 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; LCTE; rv:11.0) like Gecko"
Ожидаемый результат имени файла должны включать в себя дату и время из этих сообщений.
Пример строки, которую я хотел бы использовать, но могу изменить ее в соответствии с результатами ответов:
tar -caf "backup-logfiles-$start-til-$end.tar.gz" access.log error.log ftp.log
Любое решение можно извлечь из этих значений в $start
и $end
.
Вот ужасно запутанная однострочная оболочка (используя формат даты, который вы упомянули в чате ):
$ name=$(printf 'backup-logfiles-%s-til-%s' $(date -d "$(head -n1 logfile | grep -oP '\[\K\S+' | sed 's|/| |g; s/:/ /')" +%Y-%m-%d-%H:%M:%S) $(date -d "$(tail -n1 logfile | grep -oP '\[\K\S+' | sed 's|/| |g; s/:/ /')" +%Y-%m-%d-%H:%M:%S))
$ echo $name
logfiles-2017-01-21-14:53:49-til-2017-12-20-16:17:50
Чтобы получить начальную и конечную переменные отдельно, выполните:
$ start=$(head -n1 logfile | grep -oP '\[\K\S+' | sed 's|/|-|g; s/:/ /')
$ end=$(tail -n1 logfile | grep -oP '\[\K\S+' | sed 's|/|-|g; s/:/ /')
$ echo "backup-logfiles-$start-til-$end.tar.gz"
backup-logfiles-21-Jan-2017 14:53:49-til-20-Dec-2017 16:17:50.tar.gz
Или, если вы хотите числовую дату:
$ start=$(date -d "$(head -n1 logfile | grep -oP '\[\K\S+' | sed 's|/|-|g; s/:/ /')" +%Y-%m-%d-%H:%M:%S)
$ end=$(date -d "$(tail -n1 logfile | grep -oP '\[\K\S+' | sed 's|/|-|g; s/:/ /')" +%Y-%m-%d-%H:%M:%S)
$ echo "backup-logfiles-$start-til-$end.tar.gz"
backup-logfiles-2017-01-21-14:53:49-til-2017-12-20-16:17:50.tar.gz
Использование только sed
, только для веселья del> победы в гольфе;)
name=$(sed -rn 's|/|-|g;s/.* \[([^ ]+) .*/\1/;1p;$p' file | sed 'N;s/\n/-til-/')
$ echo $name
21-Jan-2017:14:53:49-til-20-Dec-2017:16:17:50
Но если этот файл нужно передать tar
, двоеточия могут вызвать проблемы:
An archive name that has a colon in it specifies a file or device on a remote
machine. The part before the colon is taken as the machine name or IP address,
and the part after it as the file or device pathname, e.g.:
--file=remotehost:/dev/sr0
Вы можете обойти это, передав опцию:
--force-local
Archive file is local even if it has a colon.
Но вот команда, которая заменяет двоеточия большим количеством дефисов:
name=$(sed -rn 's|[/:]|-|g;s/.* \[([^ ]+) .*/\1/;1p;$p' file | sed 'N;s/\n/-til-/')
Вместо класса символов мы могли бы использовать чередование и сохранить байт:)
name=$(sed -rn 's#/|:#-#g;s/.* \[([^ ]+) .*/\1/;1p;$p' file | sed 'N;s/\n/-til-/')
-r
использовать ERE -n
ничего не печатайте, пока мы не попросим s|/|-|g
заменить все символы /
на -
(потому что у нас не может быть имени файла с /
) s|[/:]|-|g
заменить символы /
и :
дефисами везде. s#/|:#-#g
заменить /
или :
на -
везде ;
отдельные команды sed
s/.* \[([^ ]+) .*/\1/
записывать дату и время между квадратные скобки (от первого [
до первого пробела). 1p;$p
печатать только первую строку и последнюю строку |
направлять ее в другую sed
(тьфу!) N
читать обе строки в шаблон пространство ... s/\n/-til-/
... так что мы можем заменить новую строку на -til-