我的文件中包含以下文本
---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
?
答案 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
变量指定的块,则不打印输入记录
进一步阅读:
awk '/PAT1/{flag=1} flag; /PAT2/{flag=0}'
的一种变体,在链接的问答中对此进行了解释答案 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,请删除该收藏集,否则将正常打印。