Изменить числовые значения c в строках из stdout - PullRequest
0 голосов
/ 09 февраля 2020

У меня есть входные строки, которые я хочу переписать и изменить некоторые из числовых значений c:

Ввод : src/main.tsx(2,31): error TS2304: Cannot find name 'foo'.

Желаемый результат : src/main.tsx:1:30: error: TS2304: Cannot find name 'foo'.

Обратите внимание, что:

  • Числовые значения c были уменьшены на 1.
  • error является динамическим c. Это также может быть warning.
  • Команда будет иметь ввод данных (tsc | MAGIC_HAPPENS_HERE). Если есть ошибка, то эта команда должна передать ее.

Пока у меня есть следующее: sed -E "s/^([^(]+)\(([0-9]+),([0-9]+)\): ((warning)|(error)) (.*)/\1:\2:\3: \4: \7/"

Это работает за исключением манипуляции с цифрами c. Из того, что я прочитал, я считаю, sed не подходит для работы. Я посмотрел на awk, но ударил по стене группами захвата регулярных выражений.

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

Ответы [ 2 ]

2 голосов
/ 09 февраля 2020

Не могли бы вы попробовать следующее.

awk '
match($0,/\([^)]*/){
  value=substr($0,RSTART+1,RLENGTH-1)
  num=split(value,array,",")
  for(i=1;i<=num;i++){
    val=(val?val":":"")array[i]-1
  }
  part_2=substr($0,RSTART+RLENGTH+1)
  sub(/error/,"error:",part_2)
  print substr($0,1,RSTART-1) ":" val part_2
  value=part_2=""
}'  Input_file

Вывод будет следующим.

src/main.tsx:1:30: error TS2304: Cannot find name 'foo'.

Объяснение: Добавление подробного объяснения для вышеуказанного кода.

awk '                                          ##Starting awk program here.
match($0,/\([^)]*/){                           ##Using match function to match regex from ( till ) in line.
  value=substr($0,RSTART+1,RLENGTH-1)          ##Creating variable value which has value of sub-string from RSTART+1 to RLENGTH-1.
  num=split(value,array,",")                   ##Using split, to split the value into an array named array.
  for(i=1;i<=num;i++){                         ##Running for loop from i=1 to till value of num(which is length of array).
    val=(val?val":":"")array[i]-1              ##Creating variable val whose value is subtraction of array[i] value with 1 and keep concatenating to its own value.
  }
  part_2=substr($0,RSTART+RLENGTH+1)           ##Creating variable part_2 whose value is rest of line after matched regex.
  sub(/error/,"error:",part_2)                 ##Substituting string error with error: here in rest of the line.
  print substr($0,1,RSTART-1) ":" val part_2   ##Printing sub-string from 1 to till match found, :, val and part_2 variables here.
  value=part_2=""                              ##Nullify variables value and part_2 here.
}'  Input_file                                 ##Mentioning Input_file name here.
1 голос
/ 09 февраля 2020

Я согласен, что sed не подходит. Будучи старомодным (или, может быть, просто немодным), я бы использовал Perl:

$ cat data
src/main.tsx(2,31): error TS2304: Cannot find name 'foo'.
$ perl -p -e 's/^(.*?)\((\d+),(\d+)\): (\w+) /sprintf("%s:%d:%d: %s: ", $1, $2-1, $3-1, $4)/e' data
src/main.tsx:1:30: error: TS2304: Cannot find name 'foo'.
$

Регулярное выражение лениво сопоставляет все до «(nn,mmm): », за которым следует «слово», захватывая два цифры и то, что предшествует скобкам и слову. Затем он использует модификатор /e («оценивать правую сторону как выражение» - см. Операторы, подобные цитате Regexp ), чтобы выполнять вычитания, используя sprintf() для форматирования информации. «Слово» будет захватывать error или warning или что-либо еще, все буквы, за которыми следует пробел. Вы можете использовать \S+ вместо \w+ для захвата любой последовательности непробельных символов. Я предполагаю, что разделители представляют собой одинарные пробелы; Вы можете использовать \s+ вместо пробелов, если это необходимо, чтобы соответствовать любой непустой последовательности пробелов. (Параметр -p просто означает «чтение строк из именованных файлов или стандартный ввод, если файлы не названы, выполните действия в -e '…script…' и напечатайте результат.)

Протестировано с 5.18.4 ( /usr/bin/perl в macOS Mojave 10.14.6) и 5.30.0.


Если у вас есть процесс, выдающий ошибки, то вам нужно убедиться, что ошибки отправляются в сценарий Perl - это Сценарии оболочки, а не что-либо еще.

tsc 2>&1 |
perl -p -e 's/^(.*?)\((\d+),(\d+)\): (\w+) /sprintf("%s:%d:%d: %s: ", $1, $2-1, $3-1, $4)/e'

Если вам нужен стандартный вывод команды (tsc в измененном вопросе и фрагменте сценария оболочки выше) в go где-то еще, тогда вам нужно быть осторожным (см. также Как передать в поток stderr, а не в stdout ), но возможно:

tsc 2>&1 >tsc.out |
perl -p -e 's/^(.*?)\((\d+),(\d+)\): (\w+) /sprintf("%s:%d:%d: %s: ", $1, $2-1, $3-1, $4)/e'

Канал изначально устанавливает стандартный вывод, идущий в Perl; 2>&1 отправляет туда и стандартную ошибку; >tsc.out изменяет стандартный вывод, поэтому он переходит в файл tsc.out, оставляя стандартную ошибку при переходе к каналу.

...