Обработка текста: смещение значения даты в столбце на основе значения другого столбца - PullRequest
3 голосов
/ 22 мая 2019

У меня есть текстовый файл со значением даты в формате ГГГГММДД в ​​столбце 4 и смещением месяца в столбце 5.

a1|b1|c1|20190101|1|1|11|A|D
a1|b1|c1|20190101|2|2|12|B|E
a1|b1|c1|20190101|3|3|13|C|F
a2|b2|c2|20190101|1|4|14|G|J
a2|b2|c2|20190101|2|5|15|H|K
a2|b2|c2|20190101|3|6|16|I|L

Я хотел бы заменить значение в столбце 5 логикой дата -d '(значение в столбце 4) - (значение в столбце 5) месяцы +1 месяцы + "% Y% m% d"

Таким образом, конечный результат должен выглядеть следующим образом

a1|b1|c1|20190101|20190101|1|11|A|D
a1|b1|c1|20190101|20181201|2|12|B|E
a1|b1|c1|20190101|20181101|3|13|C|F
a2|b2|c2|20190101|20190101|4|14|G|J
a2|b2|c2|20190101|20181201|5|15|H|K
a2|b2|c2|20190101|20181101|6|16|I|L

Я связал, используя awk -f offsetMonths.awk

BEGIN{
    FS="|"
    OFS = FS
}
{
#   Date field is in column 4, offset is in column 5
#   Replace column 5 with the offset date
    "date -d '"$4" -"$5" months +1 months'  +'%Y%m%d' " | getline l
    $5 = l
    print $0
}

Я получаю

a1|b1|c1|20190101|20190101|1|11|A|D
a1|b1|c1|20190101|20181201|2|12|B|E
a1|b1|c1|20190101|20181101|3|13|C|F
a2|b2|c2|20190101|20181101|4|14|G|J
a2|b2|c2|20190101|20181101|5|15|H|K
a2|b2|c2|20190101|20181101|6|16|I|L

Обратите внимание на неправильные значения смещения месяца в строках с 4 по 6

Ответы [ 3 ]

3 голосов
/ 22 мая 2019

В дополнение к ответу kvantour (который, вероятно, чище, чем мой, потому что я бы предпочел использовать встроенные функции awk, а не вызывать команды bash внутри awk), здесь исправлен ваш код:

BEGIN{
    FS="|"
    OFS = FS
}
{
#   Date field is in column 4, offset is in column 5
#   Replace column 5 with the offset date

    cmd = "date -d '"$4" -"$5-1" months'  +'%Y%m%d'" # as suggested by @kvantour
    cmd | getline result
    close(cmd)
    $5 = result
    print $0
}

Результат:

a1|b1|c1|20190101|20190101|1|11|A|D
a1|b1|c1|20190101|20181201|2|12|B|E
a1|b1|c1|20190101|20181101|3|13|C|F
a2|b2|c2|20190101|20190101|4|14|G|J
a2|b2|c2|20190101|20181201|5|15|H|K
a2|b2|c2|20190101|20181101|6|16|I|L

Больше информации здесь.

Без вызова close () awk создает дочерние процессы для запуска команд, пока в конечном итоге не запуститсявне файловых дескрипторов для большего количества конвейеров.

3 голосов
/ 22 мая 2019

Для этого вам не нужно вызывать внешнюю date утилиту или специфические для gawk функции времени, это просто математика:

$ cat tst.awk
BEGIN { FS=OFS="|" }
{
    delta = $5 - 1
    year  = substr($4,1,4)
    month = substr($4,5,2)
    day   = substr($4,7)
    month = month - delta
    if (month <= 0) {
        year--
        month += 12
    }
    $5 = sprintf("%04d%02d%02d",year,month,day)
    print
}
$
$ awk -f tst.awk file
a1|b1|c1|20190101|20190101|1|11|A|D
a1|b1|c1|20190101|20181201|2|12|B|E
a1|b1|c1|20190101|20181101|3|13|C|F
a2|b2|c2|20190101|20190101|4|14|G|J
a2|b2|c2|20190101|20181201|5|15|H|K
a2|b2|c2|20190101|20181101|6|16|I|L
2 голосов
/ 22 мая 2019

Используя GNU awk, любые преобразования даты должны выполняться с предоставленными функциями даты.Две полезные функции времени для этой задачи: mktime и strftime:

  • mktime(datespec): это преобразует строку спецификации даты,datespec в форме YYYY MM DD hh mm ss во время эпохи Unix, т.е. общее количество секунд с 1970 г. 01 01 UTC.Начиная с gawk-4.2.1 вы можете использовать utc-flag, чтобы указать, что datespec находится в UTC или нет.

  • strftime(format,timestamp): это преобразовывает эпоху-time timestamp в форматированную строку (такое же форматирование, как у команды date).Вы можете использовать utc-flag, чтобы указать, что возвращаемое время должно быть в UTC или в местном часовом поясе.

Подробнее в руководстве GNU awk

Код становится теперь: convert.awk

BEGIN {FS=OFS="|"}
{ d=$4
  time=mktime(substr(d,1,4)" "substr(d,5,2)+1-$5" "substr(d,7,2)" 00 00 00")
  $5=strftime("%Y%m%d",time)
  print
}' file

, и вы запускаете это с:

$ awk -f convert.awk file.txt

mktime замечательно добавка.Поэтому строка, которую вы передаете в форме YYYY MM DD hh mm ss, не обязательно должна быть правильной датой, вы можете иметь неверные значения.Например, строка 2019 01 32 00 00 00 эквивалентна 2019 02 01 00 00 00 и 2019 5 -10 00 00 00 эквивалентна 2019 04 20 00 00 00, а еще больше 2019 -19 -10 00 00 эквивалентна 2017 04 20 00 00

Примечание: , посколькумы изменяем время непосредственно в mktime, нам не нужно беспокоиться о переходе на летнее время (см. комментарий).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...