Uma ótima ferramenta para processamento de texto é awk . O exemplo a seguir está usando o awk padrão no FreeBSD 11.1. @RomanPerekhrest tem uma solução elegante em outra resposta se você preferir o GNU awk.
Sua entrada é separada por vírgulas. Por isso, invocamos awk
com o parâmetro -F,
.
Podemos imprimir colunas usando a instrução print
. $1
é a primeira coluna. $2
é a segunda coluna.
$ awk -F, '{ print $8 }' inputfile.csv
2017-1-5 1:07:09
2017-11-25 19:57:17
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 da linha de comando, podemos fazê-lo como parte do script. FS para o delimitador de entrada e OFS para o delimitador de saída.
$ awk 'BEGIN { FS = "," } ; { print $8 }' inputfile.csv
2017-1-5 1:07:09
2017-11-25 19:57:17
Ao trabalhar com datas, geralmente prefiro usar o date
util para garantir que eu os manipule corretamente. E eu não preciso me preocupar se estou usando o regular ou o GNU awk. Além disso, fico com uma grande falha de gordura se a data não for analisada corretamente.
O parâmetro interessante é:
-j Specify we do not want to set the date at all
-f The format string we use for input
+ The format string we use for output
Então, se executarmos isso por uma data:
$ date -j -f "%Y-%m-%d %H:%M:%S" +"%Y-%m-%d %H:%M:%S" "2017-1-5 1:07:09"
2017-01-05 01:07:09
Podemos então combinar isso com o awk. Observe como as aspas são escapadas . Este é provavelmente o maior obstáculo para um iniciante.
$ awk -F, '{ system("date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"")}' inputfile.csv
2017-01-05 01:07:09
2017-11-25 19:57:17
A chamada do sistema parece correta - mas infelizmente só nos permite capturar o código de retorno e imprime diretamente na saída. Para evitar isso, usamos o padrão cmd | getline
. O exemplo simples a seguir irá ler a data atual no mydate:
$ awk 'BEGIN { cmd = "date"; cmd | getline mydate; close(cmd); print mydate }'
Thu Mar 1 16:26:15 CET 2018
Usamos a palavra-chave BEGIN
, pois não temos dados para esse exemplo simples.
Então, vamos expandir isso:
awk 'BEGIN { FS=","; OFS=FS };
{
cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"";
cmd | getline firstdate;
close(cmd);
cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$9"\"";
cmd | getline seconddate;
close(cmd);
print $1,$2,$3,$4,$5,$6,$7,firstdate,seconddate
}' inputfile.csv
E podemos colapsá-lo para um verso:
awk 'BEGIN {FS=",";OFS=FS};{cmd="date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"";cmd | getline firstdate;close(cmd);cmd="date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$9"\"";cmd | getline seconddate;close(cmd);print $1,$2,$3,$4,$5,$6,$7,firstdate,seconddate}' inputfile.csv
O que me dá a saída:
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
Adendo
Como o objetivo aqui é aprender bons hábitos, é melhor atualizar essa resposta. É um mau hábito repetir o código. Quando você começa a fazer isso, você deve dividir as coisas em uma função. Como você perceberá, o código abaixo se torna mais legível imediatamente.
awk 'function convertdate(the_date) {
cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""the_date"\"";
cmd | getline formatted_date;
close(cmd);
return formatted_date
}
BEGIN { FS=","; OFS=FS };
{
print $1,$2,$3,$4,$5,$6,$7,convertdate($8),convertdate($9)
}' inputfile.csv
Faça disso um hábito e você perceberá como será mais fácil introduzir o tratamento de erros mais tarde.