-1

Is it possible using sed or awk or any other shell commands to recognise lines with single character e.g. ) and then replace it with something else? There could be many lines containing ) but it replaces only lines where there is single character ). Example:

exp =  ... +
     (    x  
        + 2*(y) 
        + z
      )
       + ...

What I am trying to get is the following

exp =  ... +
     (    x 
        + 2*(y) 
        + z
      }
       + ...

If I use normal sed command to replace ) it will replace all the matches with ).

sed -i -e 's/)/\}/g' file

will give

exp =  ... +
     (    x
        + 2*(y} 
        + z
      }
       + ...

Is there a way out?

EDIT: an example with nested parenthesis where a single line contain inner nested bracket, the solution does not work (for this example):

sed -e 's/(\(.*\))/{\1}/g'

      ...
   + LNb * (
      + ( - 224/27 + ( - 8/3)*Lqf^2 + (80/9)*Lqf)*CF*NF
      + (1616/27 - 56*[Zeta[3]] + ( - 536/9 + 16*[Zeta[2]])*Lqf + (44/3)*
     Lqf^2)*CF*CA
      + ((32 - 128*[Zeta[2]])*Lqf)*CF^2
      )
     + ...

which gives

      ...
   + LNb * (
      + { - 224/27 + ( - 8/3)*Lqf^2 + (80/9)*Lqf}*CF*NF
      + {1616/27 - 56*[Zeta[3]] + ( - 536/9 + 16*[Zeta[2]])*Lqf + (44/3}*
     Lqf^2)*CF*CA
      + {(32 - 128*[Zeta[2]])*Lqf}*CF^2
      )
     + ...

unlike

      ...
   + LNb * {
      + ( - 224/27 + ( - 8/3)*Lqf^2 + (80/9)*Lqf)*CF*NF
      + (1616/27 - 56*[Zeta[3]] + ( - 536/9 + 16*[Zeta[2]])*Lqf + (44/3)*
     Lqf^2)*CF*CA
      + ((32 - 128*[Zeta[2]])*Lqf)*CF^2
      }
     + ...

whereas I know how to avoid it, for example I can merge lines so that it will become a single line and then I can use the command to replace the outermost (...) to {...}. However those have some other consequences not particular to this problem.

My main query is not to work it out for these examples but to understand if it is possible to detect and replace lines containing only one character ) in a file and nothing else, where the file may have many other occurrences of ) with some characters which will be intact.

BabaYaga
  • 457
  • 5
  • 20

4 Answers4

1

You can use either something like this:

sed -e 's/(\(.*\))/{\1}/g'

Which will always replace the outermost parens with { }, like so:

$ echo 'foo ( 1 + ((f)) )' | sed -e 's/(\(.*\))/{\1}/g'
foo { 1 + ((f)) }

Or something like this, which will always replace the innermost parens:

sed -e 's/(\([^()]*\))/{\1}/'

For example,

$ echo 'foo ( 1 + ((f)) )' | sed -e 's/(\([^()]*\))/{\1}/g'
foo ( 1 + ({f}) )

Or, the exact behavior you specified in your question:

$ echo 'foo ( 1 + ((f)) )' | sed -e 's/\((.*\))/\1}/g'
foo ( 1 + ((f)) }

You can't actually do proper parenthesis replacement with a single regular expression, it'll have to be some sort of iterative process. This is because you can't count with regular expressions.

cha0site
  • 10,517
  • 3
  • 33
  • 51
  • Thanks for the reply. Unfortunately I have nested parentheses. :( Basically I am trying to replace the outermost `( ... )` by `{...}`. For the `(` I can replace using some other tag associated with that. However the outermost `)` comes only in a single line `)` and that is why the problem is that I can not use `sed` without messing up the whole occurrence. – BabaYaga Nov 25 '18 at 15:33
  • I mean you don't have nested parentheses in the same line, like in your example you don't. Can you show an example with nested parens? – cha0site Nov 25 '18 at 15:35
  • thanks for the answer. While it is very helpful to understand, however I was wondering what happens when the last parenthesis is not in a single line but breaks into a different line? i.e. for `'foo ( 1 + ((f)) )'` where the last `)` comes in a second line? – BabaYaga Nov 25 '18 at 16:02
1

With any POSIX sed:

$ sed 's/^\([[:space:]]*\))\([[:space:]]*\)$/\1}\2/' file
exp =  ... +
     (    x
        + 2*(y)
        + z
      }
       + ...
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

You could use awk if you want to have the feeling to get a bit more feeling about what is going on:

awk '(NF==1)&&($1==")") { sub(/\)/,"}") } 1'

Which reads, _if the line contains a single field and that field is the character <right-bracket> ")", then substitute in that line the bracket with what you want.

kvantour
  • 25,269
  • 4
  • 47
  • 72
  • 1
    while this is what I am looking for, your example does not give answer but syntax error in both Linux and OSX . – BabaYaga Nov 27 '18 at 07:53
  • Ahh I missed that. Thanks. However I checked that this only works in Linux. I knew that `sed` is little different in Linux and OSX. This is the first time I see that `awk` is also different? Any idea on this why it does not work in OSX? – BabaYaga Nov 27 '18 at 09:11
  • 1
    The problem is subtle. MacOS uses `nawk` which is very strict in comparison to GNU. It complains that the `)` is an illegal primary (more info [here](https://stackoverflow.com/questions/50123134/what-is-an-illegal-primary-in-awk)). I have updated it to make it work in both cases. – kvantour Nov 27 '18 at 09:30
  • MacOS used BSD awk, not nawk. BSD awk is notoriously buggy BUT it at least attempts to be POSIX compliant, e.g. it supports character classes unlike nawk. As always - get gawk... – Ed Morton Nov 27 '18 at 15:56
0

This might work for you (GNU sed):

sed 's/)/&/2;t;s//}/' file

Replace the second occurrence of ) by itself and bail out, otherwise replace it by }.

potong
  • 55,640
  • 6
  • 51
  • 83