是否可以使用 shell 命令查找和替换包含单个字符的行?

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

是否可以使用 sedawk 或任何其他 shell 命令来识别具有单个字符的行,例如) 然后换成别的? 可能有很多行包含 ),但它只替换包含单个字符 ) 的行。 示例:

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

我想得到的是以下内容

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

如果我使用普通的 sed 命令替换 ),它将用 ) 替换所有匹配项。

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

会给

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

有出路吗?

编辑:带有嵌套括号的示例,其中单行包含内部嵌套括号,解决方案不起作用(对于此示例):

sed -e 's/(\(.*\))/{}/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
      )
     + ...

这给出了

      ...
   + 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
      )
     + ...

不同于

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

而我知道如何避免它,例如我可以合并行使其成为单行,然后我可以使用命令将最外面的 (...) 替换为 {...}。然而,这些还有一些其他的后果,并不是这个问题所特有的。

我的主要问题不是为这些示例解决问题,而是了解是否有可能检测和替换文件中仅包含一个字符 ) 的行,而文件中可能有许多其他 ) 的出现,其中一些字符将完好无损。

您可以使用以下任一方式:

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

这将始终用 { } 替换最外层的括号,如下所示:

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

或类似这样的东西,它将始终替换 innermost 括号:

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

例如,

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

或者,您在问题中指定的确切行为:

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

您实际上无法用单个正则表达式进行正确的括号替换,它必须是某种迭代过程。这是因为你不能用正则表达式来计算。

这可能对你有用 (GNU sed):

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

将第二次出现的 ) 替换为自身并退出,否则将其替换为 }

使用任何 POSIX sed:

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

如果你想对正在发生的事情有更多的感觉,你可以使用awk

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

内容为,_如果该行包含一个字段并且该字段是字符 ")",则用您想要的内容替换该行中的括号。