How can I use sed to replace text and also append to end of line for the match in question?

I have a sed file which is doing many substitutions.

One of them changes ~= to match( using /=\~/ s/=\~/match( /

When doing this, I also want to add a ")" (space + end paren) at the end of the line in question (that met the original match)

I tried this with this sed line:

/=\~/ s/=\~/match(/ s/$/ )/

but I got our favorite sed: -e expression #1, char 77: unknown option tos'`
(line 77 'cos this sed has lots of other stuff (omitted)).

How can I append a ) for these lines? Can I do it within this match or do I need another line for it? I would like it to only be for these matches or I might end up adding an extra ) for "existing" match() expressions.

fwiw the full sed is..

  sed -i 's/\.should/)\.to/
          /\.to ==/s/==/eq/
          /=\~/ s/=\~/match(/ s/$/ )/  <--- line in question
          /[^}.to|end.to]\.to[[:space:]]/ s/\(\S\)/expect(\1/
          /[^}.to|end.to]\.to_not[[:space:]]/ s/\(\S\)/expect(\1/
          s/[^}.to|end.to].to[[:space:]]/).to /
          s/to_receive/to receive/
          s/to_not_receive/to_not receive/' ../_spec_seded/"$file"
  • 1
    Your recent slew of regex questions seems to suggest you're building a translator of some sort. If that is indeed the case, I suggest you look at Perl: its regular expressions are far from regular and you can easily build a BNF-like grammar in its regex flavor and use it to parse your source language. Depending on the task, even flex might be able to help. – Joseph R. Nov 10 '13 at 21:41
  • 1
    Thanks Joseph. to be honest I'm initially more focused on building my basic raw regex, sed and awk skills. Perl skills are certainly good too and Perl is fairly ubiquitous in availability. However I am using a dozen other frameworks and languages so I have to limit myself to what I handle today. I'm certainly going nuts on the {} sub-block trick I just learned! – Michael Durrant Nov 10 '13 at 22:28
  • You won't build those skills by taking advice like that given in the answer here. – mikeserv Jul 15 '15 at 23:47

Try this:

sed -r "s/=~(.*)$/match(\1)/" <filename>

Also, the error that you are getting is because sed interprets /=\~/ as a filter for the line that the operation should be performed, s/=\~/match(/ as the operation and s/$/ )/ as a flag for the operation, in this case you need to use a group and separate the expressions with a new line:

sed -re "/=\~/ {
  s/$/ )/
}" <filename>

Here is the relevant documentation about the command block {} from info sed

 A group of commands may be enclosed between `{' and `}' characters.
 This is particularly useful when you want a group of commands to
 be triggered by a single address (or address-range) match.
  • -r may not be available in all versions of sed, in which case you'd have to escape the brackets on the left-hand side of the command. So POSIX-ly, this would be: sed -e 's/=~\(.*\)$/match(\1)/' file. – evilsoup Nov 10 '13 at 21:11
  • I like this approach. So as I read it, you basically 'qualify' the initial match and then use the "block" within the {} to do what you want? Can I do this sort of stuff with the sed -i same file approach? – Michael Durrant Nov 10 '13 at 21:15
  • Added the docs about {}, so, yes, you can use it to group various commands for the same address (in your case the regular expression is the address, it could also be a line number or a range with a start and end separated by a ,), and the -i flag does not alter the script behavior, you can mix it with any sed script. – Augusto Hack Nov 10 '13 at 21:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.