Вы можете использовать для этого awk
, которая имеет специальную переменную NR
, которая отслеживает номер текущей записи с начала файла. Переменная увеличивается в конце каждой строки. При печати в блоке END
, т.е. после обработки всех входных строк, печатается номер последней обработанной записи.
printf "aa\nbb" | awk 'END { print NR }'
2
printf "aa\nbb\n" | awk 'END { print NR }'
2
Попробуйте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 и, таким образом, печатает строку В вашем случае у вас есть преимущество, заключающееся в том, что даты даны в стиле 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
распечатать текущую строку, включая любые возможные модификации.
$ 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
Использование 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