Linux 仅从文本文件中删除完全格式的行范围,而忽略只有起始分隔符的行范围

Linux 仅从文本文件中删除完全格式的行范围,而忽略只有起始分隔符的行范围,linux,awk,sed,Linux,Awk,Sed,I删除起始关键字和结束关键字之间的行,如下所述: START text1 text2 text3 START text4 END text5 text6 START test7 START test8 END 我的问题是START关键字不总是以END结尾。从上面的例子中可以看出,第一次启动并没有以END结束,而是在TEXT3之后再次启动 因此,我无法使用以下sed命令: sed '/START/,/END/d' test.txt 因为它将删除文本1到文本4以及文本7-8之间的行 但我只想删除

I删除起始关键字和结束关键字之间的行,如下所述:

START
text1
text2
text3
START
text4
END
text5
text6
START
test7
START
test8
END
我的问题是START关键字不总是以END结尾。从上面的例子中可以看出,第一次启动并没有以END结束,而是在TEXT3之后再次启动

因此,我无法使用以下sed命令:

sed '/START/,/END/d' test.txt
因为它将删除文本1到文本4以及文本7-8之间的行

但我只想删除TEXT4和TEXT8行。因此,以下输出应如下所示:

START
text1
text2
text3
text5
text6
START
text7
这个答案是一个GNU awk解决方案,它可能对所使用的高级GNU特定功能感兴趣。 否则:

如果性能不是一个问题—多个子进程、文件被多次读取,请使用

否则,请使用

如果您有GNU awk,可以尝试以下操作:

awk -v RS='(^|\n)START|END(\n|$)' '
  RT ~ "END" {
    skipped=1
    next
  }
  NF {
    print (skipped ? "" : "START\n") gensub("^\n+|\n+$", "", "g")
    skipped=0
  }
' test.txt
-v RS='^ |\nSTART | END\n |$'通过在一行中出现的单词START或END将输入拆分为多行记录

这是一个GNU扩展,因为POSIX只支持RS(输入记录分隔符)的文本单字符值。 RT~END在RT中查找子字符串END,RT是使用正则表达式匹配的记录终止符

RT是GNU特定的变量,包含在当前输入记录末尾找到的实际记录终止符。这使我们能够判断手头的记录是以开始还是结束结束 如果RT包含END,我们知道我们在一个完全形成的范围内,设置一个标志来指示我们跳过这个记录,然后通过执行next来执行跳过。 模式NF是NF>0的缩写,并确保仅当手头的记录基于RS值为非空时才执行关联块,第一个输入记录将为空;但是请注意,这也会消除相邻的起始线

是否跳过打印?:开始\n gensub^\n+\n+$,g输出当前记录:

跳过?:START\n仅当上一条记录不是完全形成的范围时,才在输出前加上START。如果是,那么它基本上只是从输入中删除,没有新的范围开始。警告:如果输入不以起始行开始,这将插入一行

gensub^\n+|\n+$,g替换当前输入记录中的所有前导和尾随换行符并返回结果,以避免输出上出现任何额外的空行

gensub是一个特定于GNU的函数,它向与POSIX兼容的同级gsub添加了额外的功能,并且与gsub不同,它不在适当的位置修改输入字符串,而是返回一个修改过的副本。 skipped=0重置指示上一条记录是完全格式范围的标志

这个答案是一个GNU awk解决方案,它可能对所使用的高级GNU特定功能感兴趣。 否则:

如果性能不是一个问题—多个子进程、文件被多次读取,请使用

否则,请使用

如果您有GNU awk,可以尝试以下操作:

awk -v RS='(^|\n)START|END(\n|$)' '
  RT ~ "END" {
    skipped=1
    next
  }
  NF {
    print (skipped ? "" : "START\n") gensub("^\n+|\n+$", "", "g")
    skipped=0
  }
' test.txt
-v RS='^ |\nSTART | END\n |$'通过在一行中出现的单词START或END将输入拆分为多行记录

这是一个GNU扩展,因为POSIX只支持RS(输入记录分隔符)的文本单字符值。 RT~END在RT中查找子字符串END,RT是使用正则表达式匹配的记录终止符

RT是GNU特定的变量,包含在当前输入记录末尾找到的实际记录终止符。这使我们能够判断手头的记录是以开始还是结束结束 如果RT包含END,我们知道我们在一个完全形成的范围内,设置一个标志来指示我们跳过这个记录,然后通过执行next来执行跳过。 模式NF是NF>0的缩写,并确保仅当手头的记录基于RS值为非空时才执行关联块,第一个输入记录将为空;但是请注意,这也会消除相邻的起始线

是否跳过打印?:开始\n gensub^\n+\n+$,g输出当前记录:

跳过?:START\n仅当上一条记录不是完全形成的范围时,才在输出前加上START。如果是,那么它基本上只是从输入中删除,没有新的范围开始。警告:如果输入不以起始行开始,这将插入一行

gensub^\n+|\n+$,g替换当前输入记录中的所有前导和尾随换行符并返回结果,以避免输出上出现任何额外的空行

gensub是一个特定于GNU的函数,它向与POSIX兼容的同级gsub添加了额外的功能,并且与gsub不同,它不在适当的位置修改输入字符串,而是返回一个修改过的副本。 skipped=0重置指示上一条记录是完全格式范围的标志


通过按行反转文件变得更容易:

$ tac test.txt | sed '/END/,/START/d' | tac
START
text1
text2
text3
text5
text6
START
test7

通过按行反转文件变得更容易:

$ tac test.txt | sed '/END/,/START/d' | tac
START
text1
text2
text3
text5
text6
START
test7
在awk中:

$ cat foo.awk
/START/ { printf "%s", b; b="" }                       # at START output buffer and empty it
{ b=b $0 ORS }                                         # gather buffer
/END/ { b="" }                                         # at empty buffer at END also
END { printf "%s", b }                                 # Thanks @mklement0, this is needed
运行它:

$ awk -f foo.awk foo
START
text1
text2
text3
text5
text6
START
test7
在awk中:

$ cat foo.awk
/START/ { printf "%s", b; b="" }                       # at START output buffer and empty it
{ b=b $0 ORS }                                         # gather buffer
/END/ { b="" }                                         # at empty buffer at END also
END { printf "%s", b }                                 # Thanks @mklement0, this is needed
运行它:

$ awk -f foo.awk foo
START
text1
text2
text3
text5
text6
START
test7

感谢您的解决方案,但它没有删除该行
s我如何知道我是否在使用GNU awk?我使用的是Ubuntu16.04并安装了gawk。Ubuntu16.04上的默认awk是,这将不起作用。如果安装了Gawk,请尝试使用Gawk而不是awk调用命令。运行awk-wv查看您的awk是什么。awk-W-v的输出:GNU awk 4.1.3,API:1.1 GNU MPFR 3.1.4,GNU mp6.1.0使用与您的示例输入非常相同的Gawk版本为我生成您想要的输出。这不是你得到的吗?如果您获得了所需的输出,那么您的示例输入数据不能代表您的问题,您需要更新它。非常感谢您提供的解决方案!我也在寻找复选标记:谢谢你的解决方案,但它没有删除行。我如何知道我是否在使用GNU awk?我使用的是Ubuntu16.04并安装了gawk。Ubuntu16.04上的默认awk是,这将不起作用。如果安装了Gawk,请尝试使用Gawk而不是awk调用命令。运行awk-wv查看您的awk是什么。awk-W-v的输出:GNU awk 4.1.3,API:1.1 GNU MPFR 3.1.4,GNU mp6.1.0使用与您的示例输入非常相同的Gawk版本为我生成您想要的输出。这不是你得到的吗?如果您获得了所需的输出,那么您的示例输入数据不能代表您的问题,您需要更新它。非常感谢您提供的解决方案!我也在寻找复选标记:@kaylum不,它是不同的。@mklement0感谢您编辑标题以使其清晰明了:@kaylum不,这是不同的。@mklement0感谢您编辑标题以使其清晰明了:是的,感谢您更新和更正我的更正:;也许还可以提到,您的awk解决方案具有与我的解决方案不同的POSIX兼容的附加优势;也许还要提到,与我的解决方案不同,您的awk解决方案具有与POSIX兼容的额外优势。基于仅适用于特定样本输入的硬编码值的解决方案没有帮助。基于仅适用于特定样本输入的硬编码值的解决方案没有帮助。