如何使用 awk 过滤文件的整个块?

How to use awk to filter entire blocks of a file?

示例输入:

void foo(void) {
  printf("hello\n");
}

// Split
void noon(void) {
  printf("lunch\n");
}

void bye(void) {
  printf("goodbye\n");
}

我想过滤掉所有以 //Split:

开头的块
void foo(void) {
  printf("hello\n");
}

void bye(void) {
  printf("goodbye\n");
}

或仅过滤那些块:

// Split
void noon(void) {
  printf("lunch\n");
}

我该怎么做?基本上只要它看到“// Split”,该行和以后的输出就会指向第二个文件。每当它看到以“}”开头的行时,它应该正常输出该行,但以后的输出将被定向回第一个文件。

如果您的实际 Input_file 与显示的示例相同,那么以下内容可能会对您有所帮助。

awk '/\/\/ Split/{non_flag=1} !non_flag; /}/ && non_flag{non_flag=""}' Input_file

如果您想打印其中包含 split 的块,那么以下内容可能会对您有所帮助。

awk '/\/\/ Split/{flag=1} flag;  /}/ && flag{flag=""}'  Input_file

两种情况都有一个awk命令(假设不会有嵌套语句function { ... { ... } ... }):

awk -v pr_split=1 \
'/^\/\/ Split/{ f = 1; n = NR }
 NR != n+1 && /.+ {/{ f = 0 }
 f && pr_split;
 !pr_split{ if (f) next; else print }' file

  • pr_split - 变量,代表 "print split" 部分。告诉是否只打印 // Split 部分或除那些
  • 之外的所有内容

仅打印 // Split 个部分:

awk -v pr_split=1 ...

输出:

// Split
void noon(void) {
  printf("lunch\n");
}

要打印除 // Split 部分以外的所有内容:

awk -v pr_split=0 ...

输出:

void foo(void) {
  printf("hello\n");
}

void bye(void) {
  printf("goodbye\n");
}

您可以像这样交替输出文件:

awk '
    BEGIN {
        f=F[0]="ofile1"
        F[1]="ofile2"
    }
    /^[/][/] *Split/ || (c && /^}$/) {
        f=F[c=!c]
    }
    { print > f }
' inputs...

如果您只想要任何一个部分,您可以使打印块以 c 为条件并删除 fF

如果"Split"只出现在评论中:

$ awk -v RS= '/Split/' file
// Split
void noon(void) {
  printf("lunch\n");
}

有点冗长,但更准确:

awk -F'\n' -v RS= ' ~ /Split/' file

当记录分隔符为空时,每条记录由空行分隔。

$ awk -v RS= -v ORS='\n\n' '/^\/\/ Split/' file
// Split
void noon(void) {
  printf("lunch\n");
}

.

$ awk -v RS= -v ORS='\n\n' '!/^\/\/ Split/' file
void foo(void) {
  printf("hello\n");
}

void bye(void) {
  printf("goodbye\n");
}

要将 "Split" 块重定向到名为 "splits" 的新文件并将其余部分打印到标准输出,可以使用 GNU awk 或 mawk(也许还有其他一些):

awk -v RS= -v ORS='\n\n' '
    { print > (/^\/\/ Split/ ? "splits" : "/dev/stdout") }
' file

或使用任何 awk:

awk -v RS= -v ORS='\n\n' '
    { out = (/^\/\/ Split/ ? "splits" : "") }
    out { print > out; next }
    { print }
' file