Bash script / awk do wprowadzenia i wyprowadzenia pliku CSV

Sep 28 2020

Mam problem z utworzeniem skryptu bash / awk / sed, który pobierałby plik CSV oddzielony przecinkami składający się z trzech kolumn (imię, nazwisko, data urodzenia) i wyświetlał inny plik CSV, który ma te same kolumny z danych wejściowych dodatkowa kolumna pokazująca różnicę między aktualną datą a datą urodzenia w latach.

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

input.csv może wyglądać tak:

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

output.csv powinien wyglądać następująco:

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

Odpowiedzi

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

Aby wyprowadzić w pliku o nazwie output-filei jednocześnie wyświetlić na 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

Lub po prostu wyślij do tego samego pliku:

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

Aby wykonać dokładniejsze obliczenia czasu, można użyć gawk„s funkcje czasowe i ciągów (za sugestią AdminBee za @). Korzystanie z danych wejściowych jako:

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

Możesz uzyskać różnicę czasu w dniach między teraz a datą wyświetlaną w każdym wierszu, stosując:

$ 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

Fragment:

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

wykonuje trzy podstawowe rzeczy dla każdej linii pliku wejściowego:

  • oblicza czas, który upłynął (w sekundach) od 1970-01-01 00:00:00 UTC (w systemach POSIX), nie licząc sekund przestępnych, z mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00)
  • oblicza różnicę czasu między powyższą wielkością a zmienną today, która zawiera liczbę sekund, które upłynęły od czasu wykonania od 1970-01-01 00:00:00 UTC.
  • dzieli różnicę czasu w sekundach przez 3600 * 24, aby uzyskać to samo w dniach, i bierze pod uwagę tylko całkowitą część wyniku, aby otrzymać całe dni int().

Możesz się tym bawić, aby uzyskać różnicę czasu w sekundach, minutach, godzinach w zależności od potrzeb. HTH

MaheshK. Sep 28 2020 at 11:49

Aby uzyskać różnicę w datach, możesz użyć tej małej funkcji bash

Użyj następujących numerów do swoich potrzeb

  • # Aby uzyskać różnicę dni : 86400
  • # Aby uzyskać różnicę lat : 31536000

Funkcja Bash

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

Stosowanie:

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

Wynik:

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

W zależności od tego, czego naprawdę chcesz:

różnica lat:

(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

wiek:

(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 i csv-header pochodzą z csv-nix-tools