Eu tenho um arquivo que contém datas de época que eu preciso converter para legível por humanos. Eu já sei como fazer a conversão de datas, por exemplo:
[server01 ~]$ date -d@1472200700
Fri 26 Aug 09:38:20 BST 2016
..mas estou lutando para descobrir como sed
percorrer o arquivo e converter todas as entradas. O formato do arquivo é assim:
#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web
text-processing
sed
date
maquinista
fonte
fonte
HISTTIMEFORMAT
variável shell para controlar o formato no momento da gravação.date -d
não é portátil para dizer Solaris ... Estou assumindo que isso esteja em um sistema com ferramentas principalmente GNU? (GNU AWK / Perl tendem a ser os métodos mais portáteis para lidar com conversões de datas).gawk '{ if ($0 ~ /^#[0-9]*$/) {print strftime("%c",substr($0,2)); } else {print} }' < file
(strftime
Parece não-portáteis ...)Respostas:
Assumindo um formato de arquivo consistente,
bash
você pode ler o arquivo linha por linha, testar se ele está no formato especificado e fazer a conversão:BASH_REMATCH
é uma matriz cujo primeiro elemento é o primeiro grupo capturado na correspondência de Regex=~
, nesse caso a época.Se você deseja manter a estrutura do arquivo:
isso produzirá o conteúdo modificado para STDOUT, para salvá-lo em um arquivo, por exemplo
out.txt
:Agora, se desejar, você pode substituir o arquivo original:
Exemplo:
fonte
bash
,printf
pode fazer a própria conversão:printf '#%(%F %H)T\n' "${BASH_REMATCH[1]}"
.Embora seja possível com o GNU
sed
com coisas como:Isso seria terrivelmente ineficiente (e é fácil introduzir vulnerabilidades arbitrárias de injeção de comando 1 ), pois isso significaria executar um shell e um
date
comando para cada#xxxx
linha, praticamente tão ruins quanto umwhile read
loop de shell . Aqui, seria melhor usar coisas comoperl
ougawk
, ou seja, utilitários de processamento de texto com recursos de conversão de data incorporados:Ou:
1 Se tivéssemos escrito em
^#([0-9]).*
vez de^#([0-9]).*$
(como fiz em uma versão anterior desta resposta), em locais de vários bytes, como UTF-8 (hoje em dia a norma), com uma entrada como#1472047795<0x80>;reboot
, em que esse<0x80>
é o valor de byte 0x80 que não formar um caractere válido, esses
comando acabaria sendo executado,date -d@1472047795<0x80>; reboot
por exemplo. Enquanto com o extra$
, essas linhas não seriam substituídas. Uma abordagem alternativa seria:,s/^#([0-9])/date -d @\1 #/e
que é deixar a parte após a#xxx
data como um comentário do shellfonte
date -f
para fazer todas as conversões de maneira otimizada para fluxo?s
sinalizador faz com que.*
também inclua a nova linha na entrada. Você também pode usarstrftime "%c", localtime $1
.Todas as outras respostas geram um novo
date
processo para cada data da época que precisa ser convertida. Isso pode aumentar a sobrecarga de desempenho se sua entrada for grande.No entanto, a data GNU tem uma
-f
opção útil que permite que uma única instância do processodate
leia continuamente as datas de entrada sem a necessidade de um novo fork. Portanto, podemos usarsed
,paste
edate
dessa maneira, de modo que cada um seja gerado apenas uma vez (2x porsed
), independentemente do tamanho da entrada:sed
comandos respectivamente excluem basicamente as linhas pares e ímpares da entrada; o primeiro também substitui#
por@
para fornecer o formato de data e hora correto da época.sed
saída é então canalizada para adate -f
qual faz a conversão de data necessária, para cada linha de entrada que ela recebe.paste
. As<( )
construções são substituições do processo bash que efetivamente enganam a pessoa a pensar que está lendo os nomes de arquivos fornecidos, quando na verdade está lendo a saída canalizada do comando interno.-d '\n'
dizpaste
para separar linhas de saída pares e ímpares com uma nova linha. Você pode alterar (ou remover) isso se, por exemplo, desejar o carimbo de data / hora na mesma linha que o outro texto.Observe que existem vários GNUisms e Bashisms neste comando. Isso não é compatível com Posix e não se espera que seja portátil fora do mundo GNU / Linux. Por exemplo,
date -f
faz outra coisa nadate
variante OSXes BSD .fonte
date -d
(da pergunta) também não é portátil ... (No FreeBSD, ele tenta mexer nas configurações de horário de verão, no Solaris, gera um erro ...) A questão não especifica um sistema operacional ...Supondo que o formato de data que você possui em sua postagem seja o que você deseja, a seguinte expressão regular deve atender às suas necessidades.
Lembre-se do fato de que isso substituirá apenas uma época por linha.
fonte
sed: -e expression #1, char 48: invalid reference \3 on 's' command's RHS
usando sed:
resultado :
como meu idioma local é o árabe :)
fonte
Minha solução como fazer isso em um pipeline
fonte