Bash скрипт / awk для ввода и вывода файла CSV

Sep 28 2020

У меня возникли проблемы с созданием сценария bash / awk / sed, который будет принимать CSV-файл с разделителями-запятыми из трех столбцов (имя, фамилию, дату рождения) и выводит другой CSV-файл с теми же столбцами из ввода с дополнительный столбец, показывающий разницу между текущей датой и датой рождения в годах.

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

input.csv может выглядеть так:

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

output.csv должен выглядеть так:

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

Ответы

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

Для вывода в файл с именем output-fileи одновременного отображения в 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

Или просто вывести в тот же файл:

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

Для выполнения более точных вычислений времени, вы можете использовать gawk«s время и строковые функции (за @ предложение AdminBee в). Использование входных данных как:

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

Вы можете получить разницу во времени в днях между настоящим моментом и датой, указанной в каждой строке, с помощью:

$ 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

Фрагмент:

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

выполняет три основных действия для каждой строки входного файла:

  • он вычисляет время, прошедшее (в секундах) с 1970-01-01 00:00:00 UTC (в системах POSIX), не считая дополнительных секунд, с mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00)
  • он вычисляет разницу во времени между указанным выше количеством и переменной today, которая содержит количество секунд, прошедших во время выполнения с 1970-01-01 00:00:00 UTC.
  • он делит разницу во времени в секундах на 3600 * 24, чтобы получить то же самое в днях, и учитывает только целую часть результата, чтобы получить целые дни int().

Вы можете поиграть с этим, чтобы получить разницу во времени в секундах, минутах, часах в зависимости от ваших потребностей. HTH

MaheshK. Sep 28 2020 at 11:49

Чтобы получить разницу в датах, вы можете использовать эту небольшую функцию bash

Используйте следующие номера для ваших нужд

  • # Чтобы получить разницу в днях : 86400
  • # По получить Years разницу: 31536000

Функция Bash

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

Применение:

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

Вывод:

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

В зависимости от того, чего вы действительно хотите:

разница в годах:

(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

возраст:

(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 и csv-header взяты из csv-nix-tools