如何删除2种模式之间的块文本?

时间:2018-07-02 14:13:58

标签: linux bash shell sed

我的文件中包含以下文本

---BEGIN TEXT---
any text1
anytext2
anytext3
---END TEXT---
---BEGIN TEXT---
any text4
any text5
---END TEXT---

我想将第二个文本块从"---BEGIN TEXT---"删除为"---END TEXT---"

如何使用linux命令做到这一点

所以我的文件将仅包含:

---BEGIN TEXT---
any text1
anytext2
anytext3
---END TEXT---

我知道如何使用以下命令删除第一个块:

sed -n '/BEGIN TEXT/,/END TEXT/{p;/PAT2/q}' file.txt

我如何修改sed命令以删除第二部分而不是第一部分?或使用其他命令,例如awk

6 个答案:

答案 0 :(得分:3)

这是通用解决方案的修改后的示例

$ cat ip.txt 
foobaz
---BEGIN TEXT---
block 1
any text
---END TEXT---
1234567
---BEGIN TEXT---
block 2
any text
---END TEXT---
helloworld
---BEGIN TEXT---
block 3
any text
---END TEXT---
42424242

仅删除第二个块:

$ awk -v b=2 '/BEGIN TEXT/{f=1; c++} !(f && c==b); /END TEXT/{f=0}' ip.txt 
foobaz
---BEGIN TEXT---
block 1
any text
---END TEXT---
1234567
helloworld
---BEGIN TEXT---
block 3
any text
---END TEXT---
42424242
  • -v b=2要删除的方块
  • /BEGIN TEXT/{f=1; c++}在启动正则表达式匹配时设置标志和增量计数器
  • /END TEXT/{f=0}清除标志以结束正则表达式
  • !(f && c==b)如果设置了标志并且是b变量指定的块,则不打印输入记录


进一步阅读:

答案 1 :(得分:3)

使用GNU awk进行多字符RS和RT:

$ awk -v RS='---END TEXT---\n' '{ORS=RT} NR==1' file
---BEGIN TEXT---
any text1
anytext2
anytext3
---END TEXT---

$ awk -v RS='---END TEXT---\n' '{ORS=RT} NR!=1' file
---BEGIN TEXT---
any text4
any text5
---END TEXT---

$ awk -v RS='---END TEXT---\n' '{ORS=RT} NR==2' file
---BEGIN TEXT---
any text4
any text5
---END TEXT---

答案 2 :(得分:2)

您可以使用sed代替awk

awk '/BEGIN TEXT/{found++} found==1{print $0}' yourfile

awk逐行处理文件。因此,在这里我们测试一下当前行中是否包含BEGIN TEXT。如果是这样,我们将found变量加1。在下一个块中,如果print $0变量等于1,则打印行found

如果文件很大,并且我们想在found大于1之后停止处理,我们可以添加一个额外的块退出

awk '/BEGIN TEXT/{found++} found==1{print $0} found>1{exit 0}' yourfile

答案 3 :(得分:1)

使用GNU awk和多行记录:

awk -v RS='---END TEXT---' 'NR==1{print $0 RT}' file

RS是记录分隔符,设置在块的末尾。

NR是记录数。在这种情况下,我们只想要第一个。

RT是记录终止符,用于存储当前记录的记录分隔符,并与所需的块一起打印。

答案 4 :(得分:0)

简而言之,sed -i '/---END TEXT---/q;' txtfile尽管我认为这并不是您想要的答案。

可以编写一个更复杂的sed脚本,该脚本执行很多保留和模式空间操作,但是。

如果您特别想要排除第二组,则可以使用bash。不比awk的答案好,但是我喜欢做出贡献。

c=0; while read line; do [[ "$line" = "---BEGIN TEXT---" ]] && (( c++ )); (( c != 2 )) && echo "$line"; done <txt

或格式化-

c=0
while read line
do [[ "$line" = "---BEGIN TEXT---" ]] && (( c++ ))
   (( c != 2 )) && echo "$line"
done < txtfile

答案 5 :(得分:0)

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

sed -r '/---BEGIN/{:a;N;/^---END/M!ba;x;s/^/x/;/^x{2}$/{x;d};x}' file

聚集---BEGIN---END之间的行,然后在保留空间(HS)中增加一个计数器。如果计数器为2,请删除该收藏集,否则将正常打印。