Манипуляции со строкой / подстрокой AWK теряют исходное форматирование

Привет, у меня есть следующий файл:

P:TWS.XAUUSD    07:34:47.872000 0       1306.73 1000    1306.87 500     0       0       99
P:TWS.XAUUSD    07:34:47.876000 0       1306.7  500     1306.87 500     0       0       99
P:TWS.XAUUSD    07:34:47.877000 0       1306.7  500     1306.85 500     0       0       99

Я хочу изменить метку времени во втором столбце (2 доллара США) и уменьшить ее на 1 час.

Я использую awk и разделяю второе поле на 2 отдельные подстроки, но когда я использую следующий код:

awk '{print $1,substr($2,1,2)-1 substr($2,3,13),$3,$4,$5,$6,$7,$8,$9,$10}'

Мой вывод выглядит так

P:TWS.XAUUSD 6:34:47.872000 0 1306.73 1000 1306.87 500 0 0 99
P:TWS.XAUUSD 6:34:47.876000 0 1306.7 500 1306.87 500 0 0 99
P:TWS.XAUUSD 6:34:47.877000 0 1306.7 500 1306.85 500 0 0 99

Расчет и информация верны, но я теряю форматирование (мне нужно, чтобы столбец часов HH был двухзначным).

Как я могу выполнить тот же расчет и сохранить исходное форматирование.

Я попытался использовать команду printf, но мне не удалось извлечь несколько полей и получить всю строку, которая мне нужна.

awk '{printf ("% 02d \ n"), $ 2-1}'

дает мне следующий результат

06
06
06

Как мне соединить print и printf?


person Cubix    schedule 13.06.2014    source источник
comment
Вам не нужны операции с подстроками, чтобы потерять форматирование; разделенный запятыми список полей в print теряет форматирование между столбцами или интервалы (только $0 сохраняет их). Вы должны будете сгенерировать одну строку формата для printf с 11 соответствующими спецификациями преобразования, по одной для каждого из ваших полей вывода.   -  person Jonathan Leffler    schedule 13.06.2014
comment
Что, если у вас есть 0:20:40 и ваш скрипт сокращает время на один час, должно ли оно стать _2 _ ???   -  person Jotne    schedule 13.06.2014
comment
Вам ДЕЙСТВИТЕЛЬНО нужно сохранить исходное форматирование или вам просто нужно, чтобы поля вывода были разделены табуляцией. Первое решить намного сложнее, чем второе (просто установите OFS="\t").   -  person Ed Morton    schedule 14.06.2014


Ответы (5)


Специальное решение для gawk, сохраняющее точный интервал между оригиналом:

gawk 'BEGIN {FIELDWIDTHS = "16 2 72"}{printf("%s%02d%s\n", $1, ($2-1>0?$2-1:23), $3)}' file

Конечно, то же самое можно было бы проделать и с подстроками.

person ooga    schedule 13.06.2014
comment
@ooga Большое спасибо, это именно то, что я искал, и это помогло! - person Cubix; 08.07.2014

Я бы рекомендовал использовать функции времени awk для выполнения арифметики времени:

awk '
    BEGIN { date = strftime("%Y %m %d", systime()) }
    {
        split($2, a, /[:.]/)
        t = mktime(date" "a[1]-1" "a[2]" "a[3])
        $2 = strftime("%T",t) "." a[4]
        print
    }
' file

Это дает то преимущество, когда время «00:00:00» выводится на печать как «23:00:00» вместо «-1: 00: 00».

Есть несколько часов в году (переход на летнее время), когда эта чрезмерно упрощенная арифметика даст неверные результаты.

person glenn jackman    schedule 13.06.2014
comment
Вы можете добавить, что для этого требуется GNU awk из-за функций времени. - person jaypal singh; 14.06.2014

Используйте OFS='\t' (разделитель выходных полей):

awk '{print $1,substr($2,1,2)-1 substr($2,3,13),$3,$4,$5,$6,$7,$8,$9,$10}' OFS='\t' file
P:TWS.XAUUSD    6:34:47.872000  0   1306.73 1000    1306.87 500 0   0   99
P:TWS.XAUUSD    6:34:47.876000  0   1306.7  500 1306.87 500 0   0   99
P:TWS.XAUUSD    6:34:47.877000  0   1306.7  500 1306.85 500 0   0   99
person anubhava    schedule 13.06.2014

Вы также можете направить вывод в команду столбца

[nabeel@nmoidu ~]$ awk '{print $1,substr($2,1,2)-1 substr($2,3,13),$3,$4,$5,$6,$7,$8,$9,$10}' test | column -t
P:TWS.XAUUSD  6:34:47.872000  0  1306.73  1000  1306.87  500  0  0  99
P:TWS.XAUUSD  6:34:47.876000  0  1306.7   500   1306.87  500  0  0  99
P:TWS.XAUUSD  6:34:47.877000  0  1306.7   500   1306.85  500  0  0  99
person Nabeel Moidu    schedule 12.09.2014

person    schedule
comment
Я бы порекомендовал использовать модуль DateTime для решения perl. Это позволит получить правильную арифметику времени. - person glenn jackman; 14.06.2014
comment
@glennjackman Я ценю ваши отзывы, и вы, конечно, можете использовать модуль, но это может быть чрезмерным убийством, поскольку у OP есть только время для беспокойства. Единственный случай, когда предложенное решение не сработает, - это полночь. Я обновил решение, чтобы справиться с этим случаем, сохранив формат, который требовался OP. Если вы считаете, что в некоторых сценариях это может сломаться, дайте мне знать, и я обновлю решение с помощью модуля :). - person jaypal singh; 14.06.2014
comment
Он также будет отказываться дважды в год для перехода на летнее время. Например, в Канаде / Востоке: date -d "2014-03-23 03:30 - 1 hour" +%H:%M равно 01:30 - поэтому, чтобы всегда быть правильным, просто вычитания 1 недостаточно. - person glenn jackman; 14.06.2014
comment
@glennjackman Верно, но без дат вы никогда не узнаете, просто посмотрев на время. :) - person jaypal singh; 14.06.2014