Processing sed matching group through another sed command

Viewed 80

I'd like to process the output of a compile done in linux, and convert all error references to use dos file paths which can be parsed by a windows IDE. So, for example if I had the following line in the unix file:

linuxroot/a/b/c/file.c:200:1: error: evil use of / character 

I'd like it to output:

d:\sftp\a\b\c\file.c:200:1: error: evil use of / character

So basically, I want to find anything that matches: ^\(linuxroot/[A-Za-z0-9_/.-]*\):[0-9]*:[0-9]*: error: \(.*\)$, and then run only the first group through another sed replacement: sed -e "s|\/|\\\\|g" -e "s|^\\\\linuxroot|d:\\\\sftp". Is there any mechanism in sed to do something like this?

6 Answers

Using sed

$ sed -E ':a;s~/([^/])(.*:)~\\\1\2~;ta;s/^linuxroot/d:\\sftp/' input_file
d:\sftp\a\b\c\file.c:200:1: error: evil use of / character

Hold it, cut it, change it, grab it, mix it [1].

sed '
  h                                 # hold the line in hold space
  s/:.*//                           # remove all after :
  s~/~\\~g                          # replaces slashes
  s/^linuxroot/d:\\sftp/            # replace linuxroot
  G                                 # append hold space
  s/\([^\n]*\)[^:]*\(.*\)/\1\2/     # shuffle pattern space
  '

Is there any mechanism in sed to do something like this?

Yes, with hold space you can implement any kind of functionality, like a stack, where you can hold stuff for grabing later.

I've come up with this:

$ cat file
linuxroot/aaaaa/file.c:200:1: error: evil use of / character
linuxroot/a/bbb/file.c:200:1: error: evil use of / character
linuxroot/a/b/c/file.c:200:1: error: evil use of / character
$ cat file.sed
\!^linuxroot/[A-Za-z0-9_/.-]*:[0-9]*:[0-9]*: error: .*! {
:loop
    # try to replace a '/' to the left of ':'
  s!^([^:]*)/([^:]*)!\1\\\2!
    # if succeeded, try again
  tloop
    # now there's no '/' to the left of ':'
  s!^linuxroot!d:\\sftp!
}
$ sed -E -f file.sed file
d:\sftp\aaaaa\file.c:200:1: error: evil use of / character
d:\sftp\a\bbb\file.c:200:1: error: evil use of / character
d:\sftp\a\b\c\file.c:200:1: error: evil use of / character

This might work for you (GNU sed):

sed '/^linuxroot.*:/{s/:/\n&/;h;y/\//\\/;s/linuxroot/d:\\sftp/;G;s/\n.*\n//}' file

If a line starts with linuxroot and matches a :.

Then insert a newline before the :, make a copy, translate all / to \, replace linuxroot by d:\sftp, append the copy and remove the portion of the pattern space between newlines.

IMHO it's simpler with GNU awk for the 3rd arg to match() and gensub():

$ awk 'match($0,"^linuxroot(/[[:alnum:]_/.-]*)(:[0-9]*:[0-9]*: error: .*)$",a) {
    $0 = "d:\\sftp" gensub("/","\\","g",a[1]) a[2]
} 1' file
d:\sftp\a\b\c\file.c:200:1: error: evil use of / character

With perl:

perl -pe 's|^linuxroot(/[\w/.-]+:\d+:\d+: error: )|"d:\\sftp" . $1 =~ s,/,\\,gr|e' ip.txt

The e flag allows you to use Perl code in the replacement section.

$1 =~ s,/,\\,gr replaces / with \ only for the first capture group. r flag is used here to return the string instead of modifying $1.

. is string concatenation operator.

Related