I agree that sed
is not the appropriate tool. Being old-fashioned (or maybe just unfashionable), I'd use 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'.
$
The regex lazily matches everything up to "(nn,mmm):
" followed by a 'word', capturing the two numbers and what precedes the brackets and the word. It then uses the /e
modifier ('evaluate the right side as an expression' — see Regexp Quote-Like Operators) to do the subtractions using sprintf()
to format the information. The 'word' will capture error
or warning
or anything else that is all letters followed by a blank. You could use \S+
in place of \w+
to capture any sequence of non-space characters. I assume the separators are single blanks; you can use \s+
in place of the blanks, if need be, to match any non-empty sequence of white space. (The -p
option simply means 'read lines from named files, or standard input if no files are named, do the actions in the -e '…script…'
and print the result.)
Tested with 5.18.4 (/usr/bin/perl
on macOS Mojave 10.14.6) and 5.30.0.
If you have a process producing errors, then you need to ensure that the errors are sent to the Perl script — that's shell scripting rather than anything else.
tsc 2>&1 |
perl -p -e 's/^(.*?)\((\d+),(\d+)\): (\w+) /sprintf("%s:%d:%d: %s: ", $1, $2-1, $3-1, $4)/e'
If you need the standard output of the command (tsc
in the amended question and the shell script fragment above) to go somewhere else, then you need to be careful (see also How to pipe stderr and not stdout), but maybe:
tsc 2>&1 >tsc.out |
perl -p -e 's/^(.*?)\((\d+),(\d+)\): (\w+) /sprintf("%s:%d:%d: %s: ", $1, $2-1, $3-1, $4)/e'
The pipe initially sets the standard output going to Perl; the 2>&1
sends standard error there too; the >tsc.out
changes standard output so it goes to the file tsc.out
, leaving standard error going to the pipe.