从 stdout 修改字符串中的数值

Modify numeric values in strings from stdout

我有要重写和修改一些数值的输入字符串:

输入src/main.tsx(2,31): error TS2304: Cannot find name 'foo'.

期望输出src/main.tsx:1:30: error: TS2304: Cannot find name 'foo'.

注意:

到目前为止,我有以下内容: sed -E "s/^([^(]+)\(([0-9]+),([0-9]+)\): ((warning)|(error)) (.*)/::: : /"

除数字操作外,此方法有效。根据我的阅读,我认为 sed 不是完成这项工作的正确工具。我查看了 awk 但遇到了正则表达式捕获组的问题。

我正在使用 MacOS。该命令不需要是可移植的。我很高兴使用 brew.

安装其他工具

能否请您尝试以下。

awk '
match([=10=],/\([^)]*/){
  value=substr([=10=],RSTART+1,RLENGTH-1)
  num=split(value,array,",")
  for(i=1;i<=num;i++){
    val=(val?val":":"")array[i]-1
  }
  part_2=substr([=10=],RSTART+RLENGTH+1)
  sub(/error/,"error:",part_2)
  print substr([=10=],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([=12=],/\([^)]*/){                           ##Using match function to match regex from ( till ) in line.
  value=substr([=12=],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([=12=],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([=12=],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.

我同意 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, -1, )/e' data
src/main.tsx:1:30: error: TS2304: Cannot find name 'foo'.
$

正则表达式延迟匹配所有内容,直到“(nn,mmm): ”后跟 'word',捕获两个数字以及括号和单词之前的内容。然后,它使用 /e 修饰符('evaluate the right side as an expression' — 请参阅 Regexp Quote-Like Operators)使用 sprintf() 进行减法以格式化信息。 'word' 将捕获 errorwarning 或任何其他所有字母后跟空格的内容。您可以使用 \S+ 代替 \w+ 来捕获任何非 space 字符序列。我假设分隔符是单个空格;如果需要,您可以使用 \s+ 代替空格,以匹配任何非空的白色序列 space。 (-p 选项仅表示“从命名文件或标准输入中读取行,如果没有命名文件,执行 -e '…script…' 中的操作并打印结果。)

已使用 5.18.4(/usr/bin/perl 在 macOS Mojave 10.14.6 上)和 5.30.0 进行测试。


如果您有一个产生错误的进程,那么您需要确保将错误发送到 Perl 脚本 — 那是 shell 脚本而不是其他任何东西。

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

如果您需要将命令的标准输出(修改后的问题中的tsc和上面的shell脚本片段)转到其他地方,那么您需要小心(另请参见How to pipe stderr and not stdout),但也许:

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

管道最初将标准输出设置为 Perl; 2>&1 也在那里发送标准错误; >tsc.out 更改标准输出,因此它转到文件 tsc.out,而标准错误则转到管道。