Ищем правильный способ печати в нужном формате с помощью awk / sed / bash.
Рассмотрим файл (awk_test.txt
) со следующим содержанием:
Checkpoint number: ckpt.123
value1: 10
value2: 10
Checkpoint number: ckpt.234
value1: 20
value2: 25
Как извлечь данные из файла и распечатать их в следующем формате с новой строки?
ckpt.123,10,10
ckpt.234,20,25
Я пробовал использовать следующую команду awk, но не все распечатывает.
awk < awk_test.txt '/ckpt/{a=$NF} /value1/{b=$NF} /value2/{c=$NF} END {printf "%s,%s,%s\n",a,b,c}'
Вы печатаете данные только в блоке END
. Конечно, вам нужен конечный блок, но вам также нужно будет печатать, когда вы дойдете до строки ckpt
, и там уже накоплены некоторые данные. Это приводит к:
awk '/ckpt/ { if (a != "") printf "%s,%s,%s\n", a, b, c; a = $NF }
/value1/ { b = $NF }
/value2/ { c = $NF }
END { printf "%s,%s,%s\n", a, b, c }'
который при использовании с вашими образцами данных дает:
ckpt.123,10,10
ckpt.234,20,25
Или вы даже можете использовать функцию для инкапсуляции печати:
awk 'function print_it() { printf "%s,%s,%s\n", a, b, c; }
/ckpt/ { if (a != "") print_it(); a = $NF}
/value1/ { b = $NF }
/value2/ { c = $NF }
END { print_it() }'
Это дает преимущество в том, что один и тот же код печати используется в обоих местах, где требуется печать.
Для GNU awk в качестве разделителя записей RS можно установить любое регулярное выражение, в этом случае можно установить значение Checkpoint number
. Разделитель полей FS может быть установлен на :
или \n
.
Таким образом линии превращаются в поля.
gawk 'BEGIN{ RS = "Checkpoint number" ; FS = ": |\n"; OFS = "," } { if (NR > 1){ print $2,$4,$6 }}' text.txt
Результат:
ckpt.123,10,10
ckpt.234,20,25
ПРИМЕЧАНИЕ: POSIX поддерживает только один символ как RS. Спасибо @EdMorton и @Rafael за ваши комментарии. Я не привык думать о переносимости.
@EdMorton Это определенно важный фактор при рассмотрении вопроса о переносимости. В свою защиту он сослался на gawk
и никогда не сказал awk
.
@Rafael Вызов gawk не сообщает читателям, что код будет работать ТОЛЬКО в gawk, он просто сообщает читателю, что плакат просто случайно использовал gawk, и даже в gawk RS - это не «строка», а регулярное выражение.
$ awk '/^Check/{if (NR>1) print rec; rec=$NF; next} {rec = rec "," $NF} END{print rec}' file
ckpt.123,10,10
ckpt.234,20,25
Это может сработать для вас (GNU sed):
sed -r 's/.*: //;N;N;s/\n[^:]*: /,/g' file
Удалите метки и замените символы новой строки запятыми для строк по модулю три.
wrt
Record Separator RS can be set to any string
- нет. В POSIX awks RS - это одиночный символ, а в GNU awk это регулярное выражение с несколькими символами, а не буквальная строка с несколькими символами.