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

如何使用awk过滤文件的整个块?,awk,gawk,Awk,Gawk,输入示例: 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"); } 或仅针对这些块进

输入示例:

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”,该行和将来的输出都会指向第二个文件。每当它看到一行以“}”开头时,它都应该像正常情况一样输出该行,但随后的输出将被定向回第一个文件。

如果您的实际输入文件与示例中所示的相同,那么下面的内容可能会对您有所帮助

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

如果您想打印包含
拆分
的块,则以下内容可能会对您有所帮助

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

两种情况下都使用一个
awk
命令(假设不存在嵌套语句
函数{…{…}
):


  • pr_split
    -变量,表示“打印拆分”部分。说明是只打印
    //拆分
    节还是打印除这些节以外的所有内容

要仅打印
//拆分
节,请执行以下操作:

awk -v pr_split=1 ...
awk -v pr_split=0 ...
输出:

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

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

要打印除
//拆分
部分以外的所有内容,请执行以下操作:

awk -v pr_split=1 ...
awk -v pr_split=0 ...
输出:

// Split
void noon(void) {
  printf("lunch\n");
}
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
为条件,并在注释中仅出现“拆分”时去掉
f
f

$ awk -v RS= '/Split/' file
// Split
void noon(void) {
  printf("lunch\n");
}
更详细一点,但更准确:

awk -F'\n' -v RS= '$1 ~ /Split/' file
当记录分隔符为空时,每个记录都由空行分隔

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

要将“Split”块重定向到一个名为“splits”的新文件并将其余部分打印到stdout,可以使用GNU awk或mawk(可能还有其他一些):

或使用任何awk:

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

可能存在嵌套语句,如
void noon(void){printf(“午餐”\n”);int a=1;if(a==2){print“not equal 2”;}}
,由于
-v
RS=
之间没有空格,因此不必要地特定于呆呆的状态。将
-vRS=
更改为
-vRS=
,则它将在任何awk中生成相同的输出。当
Split
在其他上下文中出现时,您应该收紧regexp以避免错误匹配,例如
/^\/\/Split\n/
或简单地
$1==“//Split”
@EdMorton:关于空间的好观点,关于要使用的精确regexp,我不会走这条路,其他答案提供了其他的表达方式……其他答案都有错误的方法。你有正确的方法,但条件太宽松了。如果OP有一个名为
void myspliter()
的函数,那么代码会错误地将其视为
//Split
注释。那个It’没关系,我只写我自己的答案。@Down voter,让我知道这里的Down vote的原因??我喜欢这是多么简单,但我不明白为什么它可以显示//拆分部分:
awk'/\/\/\/Split/{flag=1}flag;/}/&&flag{flag=“”}输入
但这不是:
awk'/\/\/Split/{Split=1}Split;/}/&&拆分{split=”“}输入
;拆分后,awk给了我语法错误。哦,我发现了:拆分是awk的内置函数。我只是把它大写了,一切正常。只是好奇,为什么你要写
flag=“”
,而不是
flag=0
?这两种方法似乎都奏效了。@jorgbrown,这是一种习惯,很高兴它对你有用。实际上,如果您想检查
if
condition side等,请告诉我是否还有其他查询,我很乐意在这里提供指导。尝试过这一点,但由于f不一定在第一行初始化,我得到错误“fatal:expression for'>'redirection具有空字符串值”所以我把它改成了这个
awk'BEGIN{c=0;F[0]=“ofile1”;F[1]=“ofile2”}/^\/\/*Split/|$/(c&&/^}$/){c=!c}{print>F[c]}输入
,它几乎可以工作。但是//Split部分的closing}指向了错误的文件。很好的捕获,在
BEGIN
块中定义
f
,修复了这个问题。我相应地编辑了答案。很好,但需要有一个空行来区分各个部分。但还是要谢谢你,因为在我的例子中,这可能是一个理想的特性……你得到的每个答案都依赖于你向我们展示的数据,例如,如果输入文件中有大量可能的内容(例如字符串、注释、条件块或循环中的
}
),那么你接受的答案将失败. 在发布问题以包含真正具有代表性的数据时,这一点非常重要。在这种情况下,如果块之间不总是有空行,那么您不应该在示例中的块之间总是显示空行,对于您可能关心的此任务的每一个其他构造,同上。