我同意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 Quote-Like Operators)使用sprintf() 进行减法运算以格式化信息。 “单词”将捕获error 或warning 或其他所有字母后跟空格的内容。您可以使用\S+ 代替\w+ 来捕获任何非空格字符序列。我假设分隔符是单个空格;如果需要,您可以使用\s+ 代替空白,以匹配任何非空的空白序列。 (-p 选项只是意味着'从命名文件中读取行,如果没有文件被命名,则为标准输入,执行-e '…script…' 中的操作并打印结果。)
使用 5.18.4(macOS Mojave 10.14.6 上的/usr/bin/perl)和 5.30.0 测试。
如果您有一个产生错误的进程,那么您需要确保将错误发送到 Perl 脚本——这是 shell 脚本,而不是其他任何东西。
tsc 2>&1 |
perl -p -e 's/^(.*?)\((\d+),(\d+)\): (\w+) /sprintf("%s:%d:%d: %s: ", $1, $2-1, $3-1, $4)/e'
如果您需要命令的标准输出(修改后的问题和上面的 shell 脚本片段中的tsc)去其他地方,那么您需要小心(另见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, $2-1, $3-1, $4)/e'
管道最初将标准输出设置为 Perl; 2>&1 也在那里发送标准错误; >tsc.out 更改标准输出,使其进入文件tsc.out,将标准错误留在管道中。