如何匹配 )\n{ 使用 sed?

How to match )\n{ using sed?

我需要编写一个 shell 脚本,它会在我的 .c 文件中输入一个字符串来匹配一个相当复杂的模式。

模式为:)\n{

\n{ 之间没有任何 tabs/spaces。这就是说我想匹配位于我文件第一列的 { (这是为了只匹配 )\n{ 在 C 中的函数声明之后,而不是在循环或条件之后的那些) .

void some_function_declaration(char var1, char var2) {

我已经阅读了手册、论坛,但仍然无法找到编写模式以匹配或找到相应正则表达式的正确方法。相应的输出将是:

void some_function_declaration(char var1, char var2) { time_exe(__func__, cl(clock())); rest of the function...

以下是我到目前为止想出但行不通的方法。

尝试 1

sed -i '' '/)$\n{/a time_exe(__func__, cl(clock()));' >> list_func2.c

尝试 2

sed -i '' '/)\n{ /a time_exe(__func__, cl(clock()));' >> list_func2.c

尝试 3

sed -i '' '/)/\n{/a time_exe(__func__, cl(clock()));' >> list_func2.c

很高兴听到您对此事的建议。

您应该避免使用 sed,这是一种基于行的工具,无法很好地处理此类任务。

如果您坚持使用 sed 并且正在使用 GNU sed,您可以使用 -z / --null-data 选项,这将一次读取整个文件(读取 NUL 字节分隔的记录而不是换行分隔的记录)并且将使您能够像您期望的那样使用 )\n{ 模式:

$ { echo "line1)"; echo "{line2"; } | sed -z 's/)\n{/X/g'
line1Xline2

由于这需要将整个文件加载到内存中,预计大文件的性能会很差。


如果你喜欢无法维护的乱码,你可以使用 sed 鲜为人知的 PtD 命令来解决这个问题:

sed '/)$/{N;s/)\n{/) {\n\ttime_exe(__func__, cl(clock()));/;t;P;D}'

Try it here !

这通过在遇到以 ) 结尾的行时在模式 space (N) 中加载额外的行来工作,尝试替换两行模式,如果模式不匹配,则打印 (P) 并删除 (D) 模式 space 的第一行(否则 t 分支到下一次迭代),将模式 space 中的第二行保留为下一次迭代的第一行。

使用 /first line pattern/{N;s/whole pattern/replacement/} 通常就足够了,但它可能会失败,因为 N 会占用您不会测试第一行模式的行。这是说明 here.

我同意@Aaron 的观点,但如果你仍然想要 sed,请看这个:

$  cat /tmp/del.txt
void some_function_declaration(char var1, char var2)
{
  ...
}
void enother_function_declaration(char var1, char var2)
{
  ...
}

并应用 sed:

$ cat /tmp/del.txt | sed ':a;N;$!ba;s/)\n{/)\{\ntime_exe(__func__, cl(clock()));/g'
void some_function_declaration(char var1, char var2){
time_exe(__func__, cl(clock()));
  ...
}
void enother_function_declaration(char var1, char var2){
time_exe(__func__, cl(clock()));
  ...
}

我觉得这看起来像你想要的

UPD

让我解释一下..

更多的跨平台兼容语法是:

sed -e ':a' -e 'N' -e'$!ba' -e 's/)\n{/)\n{ ... ;/g'

哪里

  • ':a' - 创建一个分支标签(命名为a),稍后可以返回
  • 'N' - 将下一行附加到当前行(中间有 \n
  • '$!ba' - 如果下一行是最后一行
  • ,则跳转到标签a
  • 's/)\n{/)\n{ ... ;/g' - 在单行中进行 global 替换,由所有行和 \ns
  • 组成

这可能适合您 (GNU sed):

sed ':a;/)$/!b;n;/^{/!ba;c{ time_exe(__func__, cl(clock()));' file

如果当前行不以 ) 结尾,则中断 sed 的任何进一步处理。否则,打印当前行并读入下一行。如果该行不是以 { 从头检查,否则将其更改为所需格式。

也可以附加或插入所需的格式,见下文:

sed ':a;/)$/!b;n;/^{/!ba;a{ time_exe(__func__, cl(clock()));' file

或者,

sed ':a;/)$/!b;n;s/^{/& time_exe(__func__, cl(clock()));/;Ta' file

Perl 可用于此:

$ cat file.c
void some_function_declaration(char var1, char var2)
{
    if (a)
    { b; }
}
void func2()
{
    //
}
$ perl -0777 -pe 's {\)\n\{} {$& some other stuff;\n}g' file.c
void some_function_declaration(char var1, char var2)
{ some other stuff;

    if (a)
    { b; }
}
void func2()
{ some other stuff;

    //
}

由于将整个文件读入内存,所以与 相同。