Bash script / awk per inserire e produrre un file CSV

Sep 28 2020

Ho qualche problema a creare uno script bash / awk / sed che richiederebbe un file CSV separato da virgole di tre colonne (nome, cognome, data di nascita) e restituisce un altro file CSV con le stesse colonne dall'input con un colonna aggiuntiva che mostra la differenza tra la data corrente e la data di nascita in anni.

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

input.csv potrebbe essere simile a questo:

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

output.csv dovrebbe essere simile a questo:

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

Risposte

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

Per output-fileeseguire l' output in un file denominato e visualizzare contemporaneamente in STDOUT:

$ 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 solo per eseguire l'output nello stesso file:

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

Per eseguire calcoli di tempo più accurati, è possibile utilizzare gawkle funzioni di tempo e stringa di (secondo il suggerimento di @ AdminBee). Utilizzo dei dati di input come:

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

Puoi ottenere una differenza di orario in giorni tra adesso e la data mostrata su ogni riga, 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

Lo snippet:

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

fa tre cose fondamentali per ogni riga del file di input:

  • calcola il tempo trascorso (in secondi) dal 1970-01-01 00:00:00 UTC (su sistemi POSIX), senza contare i secondi intercalari, con mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00)
  • calcola la differenza di tempo tra la quantità di cui sopra e la variabile today, che contiene il numero di secondi trascorsi al momento dell'esecuzione dal 1970-01-01 00:00:00 UTC.
  • divide la differenza di tempo in secondi per 3600 * 24 per ottenere lo stesso in giorni e considera solo la parte intera del risultato, per ottenere giorni interi int().

Puoi giocarci per ottenere la tua differenza di orario in secondi, minuti, ore secondo le tue necessità. HTH

MaheshK. Sep 28 2020 at 11:49

Per ottenere la differenza di data, puoi usare questa piccola funzione bash

Usa i seguenti numeri per le tue esigenze

  • #Per ottenere la differenza di giorni : 86400
  • #Per ottenere la differenza di anni : 31536000

Funzione Bash

datediff() {
  current_date=$(date -d "$1" +%s)
  birth_date=$(date -d "$2" +%s)
  echo $(( (current_date - birth_date) / 31536000)) Years
}

Utilizzo:

datediff '9/28/2020' '1/1/1999'

Produzione:

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

A seconda di cosa vuoi veramente:

differenza di anni:

(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

età:

(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 provengono da csv-nix-tools