Como obter informações específicas de duas linhas de texto e montar um nome de arquivo a partir desse

2

Atualmente, estou escrevendo um script para arquivar alguns arquivos de log e desejá-los combinados em um único arquivo, que é nomeado de acordo com a data e hora da primeira e da última linhas em um dos arquivos de log (por exemplo, access.log). / p>

Mas, para o melhor de mim, não consigo entender como obter essas informações das linhas e montá-las em um nome de arquivo.

as linhas em questão são de um arquivo apache.log que eu poderia obter com head e tail :

Exemplo:

$ 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"

O resultado do nome do arquivo esperado deve incluir os carimbos de data e hora dessas mensagens.

Exemplo de linha que gostaria de usar, mas posso alterar isso de acordo com os resultados das respostas:

tar -caf "backup-logfiles-$start-til-$end.tar.gz" access.log error.log ftp.log

Qualquer solução é bem-vinda para extrair esses valores em $start e $end .

    
por Videonauth 20.12.2017 / 18:11

2 respostas

2

Aqui está um one-liner de shell horrivelmente complicado (usando o formato de data mencionado no bate-papo ):

$ 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

Para obter as variáveis de início e fim separadamente, faça:

$ 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

Ou, se você quiser uma data numérica:

$ 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
    
por terdon 20.12.2017 / 18:15
2

Usando apenas sed , apenas para diversão ganhar golfe;)

name=$(sed -rn 's|/|-|g;s/.* \[([^ ]+) .*//;1p;$p' file | sed 'N;s/\n/-til-/')
$ echo $name
21-Jan-2017:14:53:49-til-20-Dec-2017:16:17:50

Mas se esse arquivo é algo que você deseja passar para tar , os dois pontos podem causar problemas:

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

Você pode contornar isso passando uma opção:

--force-local
      Archive file is local even if it has a colon.

Mas aqui está um comando que substitui os dois-pontos por mais hífens:

name=$(sed -rn 's|[/:]|-|g;s/.* \[([^ ]+) .*//;1p;$p' file | sed 'N;s/\n/-til-/')

Em vez de uma classe de caracteres, podemos usar a alternância e salvar um byte :)

name=$(sed -rn 's#/|:#-#g;s/.* \[([^ ]+) .*//;1p;$p' file | sed 'N;s/\n/-til-/')

Notas

  • -r use ERE
  • -n não imprime nada até pedirmos
  • s|/|-|g substitui todos os caracteres / por - (porque não podemos ter um nome de arquivo com / )
  • s|[/:]|-|g replace / e : caracteres com hífens em todos os lugares.
  • s#/|:#-#g replace / ou : com - em todos os lugares
  • ; separate sed comandos
  • s/.* \[([^ ]+) .*// captura a data e a hora entre os colchetes (do primeiro [ para o primeiro espaço).
  • 1p;$p imprime apenas a primeira linha e a última linha
  • | canaliza para outro sed (ugh!)
  • N leu as duas linhas no espaço do padrão ...
  • s/\n/-til-/ ... para que possamos substituir a nova linha por -til-
por Zanna 20.12.2017 / 18:36