简体   繁体   中英

Is it possible to find and replace line containing single character using shell commands?

Is it possible using sed or awk or any other shell commands to recognise lines with single character eg ) 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.

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.

With any POSIX sed:

$ sed 's/^\([[:space:]]*\))\([[:space:]]*\)$/\1}\2/' file
exp =  ... +
     (    x
        + 2*(y)
        + z
      }
       + ...

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.

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 } .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM