Сдвиг дат в CSV-файле с помощью bash-скрипта

Вы можете использовать для этого awk, которая имеет специальную переменную NR, которая отслеживает номер текущей записи с начала файла. Переменная увеличивается в конце каждой строки. При печати в блоке END, т.е. после обработки всех входных строк, печатается номер последней обработанной записи.

printf "aa\nbb" | awk 'END { print NR }'
2

printf "aa\nbb\n" | awk 'END { print NR }'
2
0
12.10.2021, 12:39
4 ответа

Попробуйтеawk:

awk -v today=$(date +%Y%m%d) '
    BEGIN{FS=OFS=","}
    substr($1,2)<today{$1="D"today;}
1' file
  • -v today=$(date +%Y%m%d)Установите переменную с текущей датой.
  • BEGIN{FS=OFS=","}Устанавливает разделитель входного(FS)и выходного(OFS)полей.
  • substr($1,2)<todayОтрезать Dот первого поля и сравнить его с текущей датой.
  • $1="D"today;Заменить первое поле текущей датой
  • 1Всегда возвращает значение true и, таким образом, печатает строку
4
12.10.2021, 13:25

В вашем случае у вас есть преимущество, заключающееся в том, что даты даны в стиле ISO, что означает, что их можно интерпретировать как целые значения и просто сравнивать с помощью арифметических операторов (<, =и >), при этом получая правильные значения. заказ.

Итак, вы можете использовать следующую awkпрограмму:

awk -v cur="20211011" 'BEGIN{FS=OFS=","} {ldate=substr($1,2); if (ldate<cur) $1="D" cur} 1' input.csv

Текущая дата определяется как awkпеременная cur. В начале разделитель полей для ввода и вывода установлен на ,. Затем для каждой строки дата строки определяется путем удаления первого символа из поля 1 строки. Если результирующее «целое число» меньше cur, поле перезаписывается конкатенацией Dи содержимого cur. Кажущийся «отклоняющимся» 1за пределами блока правил предписывается awkраспечатать текущую строку, включая любые возможные модификации.

5
12.10.2021, 13:25
$ awk -v d='D20211011' 'BEGIN{FS=OFS=","} $1<d{$1=d} 1' file
D20211011,S0519,306668,1
D20211004,S1600,306668,1
D20211009,S1604,306668,1
D20211010,S1605,306668,1
D20211006,S1610,306668,1
D20211011,S1611,306668,1

$ awk -v d="$(date +'D%Y%m%d')" 'BEGIN{FS=OFS=","} $1<d{$1=d} 1' file
D20211012,S0519,306668,1
D20211012,S1600,306668,1
D20211012,S1604,306668,1
D20211012,S1605,306668,1
D20211012,S1610,306668,1
D20211012,S1611,306668,1
2
12.10.2021, 15:04

Использование Raku (, ранее известного как Perl _6)

raku -pe 's/ ^^ D <(\d*?)> \, /20211011/;'

Как отмечает @StéphaneChazelas в комментарии к вашему OP, неясно, появятся ли когда-либо «будущие даты» в вашем первом столбце. Если нет, то достаточно простой s///замены, что и выполняет приведенный выше код Раку (, заменяя все найденные цифры даты независимо от числового < = >сравнения ).

Однако, если вы хотите обновить первый столбец до значения, основанного на числовом < = >сравнении, вы можете использовать приведенный ниже код Raku, который выполняет блок, содержащий тернарный оператор Raku в замещающей половине s///оператор:

raku -pe 'my Int $d=20211011; s/ ^^ D (\d*?) \, /D{$0 < $d ?? $d !! $0},/;'

Образец ввода:

D20211011,S0519,306668,1
D20211004,S1600,306668,1
D20211009,S1604,306668,1
D20211010,S1605,306668,1
D20211006,S1610,306668,1
D20211011,S1611,306668,1

Пример вывода (для любого примера кода Raku, приведенного выше):

D20211011,S0519,306668,1
D20211011,S1600,306668,1
D20211011,S1604,306668,1
D20211011,S1605,306668,1
D20211011,S1610,306668,1
D20211011,S1611,306668,1

Для второго примера кода Раку обратите внимание, что переменная $dимеет тип -, ограниченный значением Int, в качестве дополнительной проверки правильности. И, как отмечает @AdminBee, вам повезло, что первый столбец содержит даты ISO, которые можно сравнить с операторами < = > и по-прежнему давать правильный результат.

Что касается (простой )второй строки кода Raku выше, вы должны отметить, что нет проверки $0захвата, чтобы гарантировать действительные даты (, например. гарантируя отсутствие 13-го месяца и 32-го дня ). Нет даже кода для исключения неполных дат (, например. месяц/день без год ).

OTOH, добавление соответствующей проверки даты -должно быть относительно простым, используя встроенный Raku -для поддержки объектов Dateи DateTime(никаких дополнительных модулей не требуется; пример и ссылка ниже ).

$ echo "2020-02-29" | raku -ne '.Date.raku.say'
Date.new(2020,2,29)

$ echo "2021-02-29" | raku -ne '.Date.raku.say'
Day out of range. Is: 29, should be in 1..28
  in block <unit> at -e line 1

https://docs.raku.org/language/temporal#index-entry-Date_and_time_functions
https://raku.org

0
14.10.2021, 16:21

Теги

Похожие вопросы