Using sed to replace two patterns within a larger pattern

find and replacesed

Using sed how could I replace two patterns within a larger pattern on a single line?

Given a single line of text I want to find a pattern (Let's call this the outer pattern) and then within that outer pattern replace two inner patterns.

Here's a one line example of the input text:

Z:\source\private\main\developer\foo\setenv.sh(25):     export 'FONTCONFIG_PATH'="$WINE_SHARED_SUPPORT/X11/etc/fonts"

In the example above the outer pattern is /^.*\([[:digit:]]+\):/ which should equal Z:\source\private\main\developer\foo\setenv.sh(25): The two inner patterns are /^[A-Za-z]:/ and /\\/.

Another way to phrase my question is:

Using sed I know how to perform replacements of a pattern using the s command, but how do I limit the range of s command so it only works on the portion of the input string up to the (25):?

The ultimate result I am trying to get is the line of text is transformed into this:

/enlistments/source/private/main/developer/foo/setenv.sh(25):     export 'FONTCONFIG_PATH'="$WINE_SHARED_SUPPORT/X11/etc/fonts"

Best Answer

This command converts your input example to your output example:

sed 's|\\|/|g;s|^[^/]*|/enlistments|'

If some of your input contains backslashes in the portion after the /^.*([[:digit:]]+):/ part, then you will have to divide and conquer to prevent those latter backslashes from being replaced.

sed 'h;s/^.*([[:digit:]]\+)://;x;s/^\(.*([[:digit:]]\+):\).*/\1/;s|\\|/|g;s|^[^/]*|/enlistments|;G;s/\n//'

Explanation (steps marked with an asterisk ([*]) apply to both commands):

  • h - copy the line to hold space
  • s/^.*([[:digit:]]\+):// - delete the first part of the line from the original in pattern space
  • x - swap pattern space and hold space
  • s/^\(.*([[:digit:]]\+):\).*/\1/ - keep the first part of the line from the copy (discard the last part)
  • s|\\|/|g - [*] change all the backslashes to slashes (in the divide-and-conquer version, only the portion in pattern space - the first part of the line - is affected)
  • s|^[^/]*|/enlistments| - [*] change whatever appears before the first slash into "/enlistments" - this could be made more selective if needed
  • G - append a newline and the contents of hold space onto the end of pattern space
  • s/\n// - remove the interior newline
Related Question