Eu tenho um csv contendo a seguinte estrutura de dados:
1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-1-5 1:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
Desejo exibir as datas, mês e dia, sempre com 2 dígitos. Eu também quero que o campo times Hour sempre tenha 2 dígitos.
Essencialmente adicionando zeros à esquerda se os campos mês/dia/hora tiverem apenas um único dígito, como na linha de exemplo acima.
Usando o awk, como eu faria para alcançar o seguinte resultado:
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
Uma ótima ferramenta para processamento de texto é o awk . O exemplo a seguir está usando o awk padrão simples no FreeBSD 11.1. @RomanPerekhrest tem uma solução elegante em outra resposta, se você preferir GNU awk.
Sua entrada é separada por vírgula. Por causa disso, invocamos
awk
com o-F,
parâmetro.Podemos então imprimir colunas usando a
print
instrução.$1
é a primeira coluna.$2
é a segunda coluna.Isso nos dá a 8ª coluna para cada linha.
Este é o campo de data que você deseja manipular. Em vez de definir o delimitador usando o parâmetro de linha de comando, podemos fazer isso como parte do script. FS para o delimitador de entrada e OFS para o delimitador de saída.
Ao trabalhar com datas, geralmente prefiro usar o
date
utilitário para garantir que as manipule corretamente. E não preciso me preocupar se estou usando awk regular ou GNU. Além disso, recebo uma grande falha se a data não for analisada corretamente.Os parâmetros interessantes são:
Então, se executarmos isso para uma data:
Podemos então combinar isso com awk. Observe como as aspas são escapadas . Este é provavelmente o maior obstáculo para um iniciante.
A chamada do sistema parece correta - mas infelizmente ela só nos permite capturar o código de retorno e imprimir diretamente na saída. Para evitar isso, usamos o
cmd | getline
padrão. O exemplo simples a seguir lerá a data atual em mydate:Usamos a palavra-
BEGIN
chave porque não temos entrada para este exemplo simples.Então vamos expandir isso:
E podemos recolhê-lo para um one-liner:
O que me dá a saída:
Termo aditivo
Como o objetivo aqui é aprender um bom hábito, é melhor atualizar esta resposta. É um mau hábito repetir o código. Quando você começar a fazer isso, você deve dividir as coisas em uma função. Como você notará, o código abaixo se torna imediatamente mais legível.
Faça disso um hábito e você notará como será mais fácil introduzir o tratamento de erros mais tarde.
Se você tiver o GNU awk, poderá converter o campo final em uma string datespec separada por espaços em branco e, em seguida, reformatá-lo conforme desejado usando
strftime
:Veja o Guia do Usuário do GNU awk: Funções de Tempo
Solução GNU direta
awk
:gsub(/\<[0-9]\>/, "0&", <field>)
- substitua/complemente apenas dígitos únicos autônomos dentro da string de data e hora:\<
e\>
- são limites de palavras&
- representa a substring precisa que foi correspondida pelo padrão regexpA saída:
Ele substitui todos os dígitos sozinhos, que são precedidos por
[-: ]
caracteres e seguidos por quaisquer caracteres que não sejam palavras.Esta solução é curta e simples, mas propensa a erros, porque não verifica o padrão de data e apenas adiciona zero à esquerda a dígitos isolados, que estão de acordo com o
[-: ][0-9]\b
padrão (\b
- corresponde a um limite de palavra). Mas como variante.Entrada
Resultado
O pacote dateutils tem códigos para lidar com os detalhes de dados formatados de hora/data.
produzindo:
Em um sistema como:
Alguns detalhes para dconv:
Muitas felicidades ... felicidades, drl