Bash script / awk para ingresar y generar un archivo CSV

Sep 28 2020

Tengo problemas para crear un script bash / awk / sed que tomaría un archivo CSV separado por comas de tres columnas (nombre, apellido, fecha de nacimiento) y generaría otro archivo CSV que tiene las mismas columnas de la entrada con un columna adicional que muestra la diferencia entre la fecha actual y la fecha de nacimiento en años.

$ yourscript <input CSV file> <output CSV file>

input.csv puede verse así:

bob,wag,06/13/1958
ashley,hay,01/23/1983
evan,bert,09/11/1972

output.csv debería verse así:

bob,wag,06/13/1958,62
ashley,hay,01/23/1983,37
evan,bert,09/11/1972,48

Respuestas

3 Cbhihe Sep 28 2020 at 14:46
$ cat data
bob,wag,06/13/1958
ashley,hay,01/23/1983
evan,bert,09/11/1972

Para generar un archivo con nombre output-filey mostrarlo en STDOUT al mismo tiempo:

$ 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

O simplemente enviar al mismo archivo:

$ awk -v year=$(\date +%Y) 'BEGIN{FS="/"} {print $0 "," year-$3}' data > output-file
2 Cbhihe Sep 30 2020 at 18:04

Para realizar cálculos de tiempo más precisos, puede usar gawklas funciones de cadena y tiempo (según la sugerencia de @ AdminBee). Usando datos de entrada como:

$ cat data
bob,wag,06/13/1958
ashley,hay,01/23/1983
evan,bert,09/11/1972

Puede obtener una diferencia horaria en días entre ahora y la fecha que se muestra en cada línea, con:

$ 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

El fragmento:

int((today-mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00))/(3600*24))

hace tres cosas básicas para cada línea del archivo de entrada:

  • calcula el tiempo transcurrido (en segundos) desde 1970-01-01 00:00:00 UTC (en sistemas POSIX), sin contar los segundos intercalares, con mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00)
  • calcula la diferencia de tiempo entre la cantidad anterior y la variable today, que contiene el número de segundos transcurridos en el momento de la ejecución desde 1970-01-01 00:00:00 UTC.
  • divide la diferencia de tiempo en segundos por 3600 * 24 para obtener lo mismo en días, y solo considera la parte entera del resultado, para obtener días completos int().

Puedes jugar con eso para obtener tu diferencia de tiempo en segundos, minutos, horas según tus necesidades. HTH

MaheshK. Sep 28 2020 at 11:49

Para obtener la diferencia de fecha, puede usar esta pequeña función bash

Utilice los siguientes números para sus necesidades

  • #Para obtener diferencia de días : 86400
  • #Para obtener años de diferencia: 31536000

Función 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'

Salida:

 21 years
MarcinŚlusarz Jan 09 2021 at 09:58

Dependiendo de lo que realmente quieras:

años de diferencia:

(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

años:

(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 y csv-header son de csv-nix-tools