Bash script / awk para entrada e saída de um arquivo CSV
Estou tendo problemas para criar um script bash / awk / sed que pegaria um arquivo CSV separado por vírgulas de três colunas (nome, sobrenome, data de nascimento) e gera outro arquivo CSV que tem as mesmas colunas de entrada com um coluna adicional que mostra a diferença entre a data atual e a data de nascimento em anos.
$ yourscript <input CSV file> <output CSV file>
input.csv pode ter a seguinte aparência:
bob,wag,06/13/1958
ashley,hay,01/23/1983
evan,bert,09/11/1972
output.csv deve ter a seguinte aparência:
bob,wag,06/13/1958,62
ashley,hay,01/23/1983,37
evan,bert,09/11/1972,48
Respostas
$ cat data
bob,wag,06/13/1958
ashley,hay,01/23/1983
evan,bert,09/11/1972
Para produzir em um arquivo denominado output-filee exibi-lo em STDOUT ao mesmo tempo:
$ awk -v year=$(\date +%Y) 'BEGIN{FS="/"} {print $0 "," year-$3}' data | tee output-file
bob,wag,06/13/1958,62
ashley,hay,01/23/1983,37
evan,bert,09/11/1972,48
Ou apenas para o mesmo arquivo:
$ awk -v year=$(\date +%Y) 'BEGIN{FS="/"} {print $0 "," year-$3}' data > output-file
Para realizar cálculos de tempo mais precisos, você pode usar gawkas funções de tempo e string (por sugestão de @AdminBee). Usando dados de entrada como:
$ cat data
bob,wag,06/13/1958
ashley,hay,01/23/1983
evan,bert,09/11/1972
Você pode obter uma diferença de tempo em dias entre agora e a data mostrada em cada linha, com:
$ awk -F, 'BEGIN{today=systime()}
{print $0 "," int((today-mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00))/(3600*24))}' \
data | tee output-file
bob,wag,06/13/1958,22755
ashley,hay,01/23/1983,13765
evan,bert,09/11/1972,17551
O snippet:
int((today-mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00))/(3600*24))
faz três coisas básicas para cada linha do arquivo de entrada:
- calcula o tempo decorrido (em segundos) desde 01/01/1970 00:00:00 UTC (em sistemas POSIX), sem contar os segundos bissextos, com
mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00) - ele calcula a diferença de tempo entre a quantidade acima e a variável
today, que contém o número de segundos decorridos no momento da execução desde 01/01/1970 00:00:00 UTC. - ele divide a diferença de tempo em segundos por 3600 * 24 para obter o mesmo em dias, e considera apenas a parte inteira do resultado, para obter dias inteiros
int().
Você pode brincar com isso para obter a diferença de tempo em segundos, minutos, horas de acordo com sua necessidade. HTH
Para obter a diferença de data, você pode usar esta pequena função bash
Use os seguintes números para suas necessidades
- #Para obter a diferença de dias : 86400
- #Para obter a diferença de anos : 31536000
Função Bash
datediff() {
current_date=$(date -d "$1" +%s)
birth_date=$(date -d "$2" +%s)
echo $(( (current_date - birth_date) / 31536000)) Years
}
Uso:
datediff '9/28/2020' '1/1/1999'
Resultado:
21 years
Dependendo do que você realmente deseja:
anos de diferença:
(echo "firstname,lastname,d"; cat input.csv) | csv-sqlite \
"select *, strftime('%Y', 'now') - substr(d, 7, 4) as year_diff
from input" | csv-header --remove
era:
(echo "firstname,lastname,d"; cat input.csv) | csv-sqlite
"select *, strftime('%Y', 'now') - substr(d, 7, 4) -
case when strftime('%m%d', 'now') >= (substr(d, 1, 2) || substr(d, 4, 2))
then 0 else 1 end as age
from input" | csv-header --remove
csv-sqlite e csv-header são de csv-nix-tools