我有一个如下文件。我想在其中单独删除特定子标题下的行。我尝试使用一些 sed 和 awk 命令,但无法得到它。任何人都可以帮忙用一些linux命令来破解这个问题吗?
[first attempt]
a=10
b=20
[second attempt]
a=20
b=20
[third attempt ]
a=30
b=50
我想单独删除“[第二次尝试]”子标题下的行。输出应如下所示。我只想删除子标题下的内容,并且可以选择将删除的行替换为一个空行
[first attempt]
a=10
b=20
[second attempt]
[third attempt ]
a=30
b=50
答案1
awk -v blkid=0 -v rmblk=2 '{
if ( $1 ~ /^\[/) {
blkid+=1;blkn=NR;print };
if ( blkid !=rmblk && NR!=blkn )
print ;
else if(blkid ==rmblk && NF == 0)
print ""}' file.txt
每个块的 id 从 1 开始,每个块递增 1:blkid
。
您要删除的块的块 ID:rmblk
当第一个字段以 开头时,每个块将开始[
。
该变量blkn
存储NR值[first attempt] [second attempt]
等。
答案2
sed '$!N;/^\[second/,/^\n\[/P;D' <infile >outfile
这可能应该可以,尽管我不太清楚您想要如何处理下一部分之前的尾随空白行。此输出包含它,因为这似乎是正确的做法,但如果您只想从任何部分中删除最后一个空白行,这可以相对轻松地完成 - 所以只需询问即可。
!
基本上,对于不是最后一个的每个输入行$
,sed
也会拉入N
ext 行并将其附加到插入的\n
ewline 字符分隔符之后的模式空间中。每次发生这种情况时,模式空间都会发生变化:
^Line1\nLine2$
^Line2\nLine3$
^Line3\nLine4$
如果当前模式空间与模式匹配^\[second
或者^\n\[
或这两者之间出现的任何行,sed
将P
打印到\n
模式空间中第一个出现的 ewline - 因此每次迭代只打印其缓冲区的一半。
最后,sed
D
删除\n
模式空间中第一个出现的 ewline 并从顶部再次启动脚本 - 这就是我们获得移位效果的方式。这被称为滑动窗口。它工作得很好,而且速度相当快。
我想这个问题有多个版本之类的?不管怎样,走相反的路并不难,真的。
你可能会这样做...
sed -ne '/^\[[^s]/,/^\[s/p' <in >out
这只会打印不跟随以字符开头的标题的任何内容s
,以及所有标题。不过,它并没有在之后执行整洁的小换行符:
[first attempt]
a=10
b=20
[second attempt]
[third attempt ]
a=30
b=50
如果你想更明确一点,你也可以这样做:
sed '/^\[[second]/P;$!N;//,/\n$/!P;D' <in >out
...这确实做了整洁的小换行...
[first attempt]
a=10
b=20
[second attempt]
[third attempt ]
a=30
b=50
所有这些都是sed
范围,对于每个匹配表达式,如下所示:
/match1/,/match2/command
...sed
将应用command
到两个匹配的行以及之间的所有行。
答案3
您也可以使用简短的sed
脚本来完成此操作。将以下内容放入文件中:
/second/ {
n
: del
/./ ! b
N
s/.*\n//
b del
}
叫它script
。然后使用sed -f script myfile
.如果您尝试就地编辑文件,请使用sed -i -f script myfile
,但我建议您在尝试之前运行第一个命令,并确保它正是您想要的输出。
解释:
一旦找到该字符串second
,sed 将查看下一行。如果该行不为空,则将其丢弃并查看文件中的下一行,直到找到空行。该空行和文件中的所有其他行都会被打印。 (除非有另一行包含字符串second
,在这种情况下会重复该过程。)
(如果有人感兴趣的话我可以解释更多。)
答案4
我将尝试 grep 到“第二次尝试”和“第三次尝试”的两个行号,然后删除中间的任何内容。根据您的需要进行相应编辑。 :)
#getting line number for [second attempt]
line_num_second=$(grep -n "second attempt" yourfile.txt | cut -d : -f 1)
#getting line number for [third attempt]
line_num_third=$(grep -n "third attempt" yourfile.txt | cut -d : -f 1)
start=$(expr $line_num_second +1)
end=$(expr $line_num_third -2)
#removes the content in between [second attempt] and [third attempt]
sed $start,"$end"d yourfile.txt
# sed -i $start,"$end"d yourfile.txt # -i - overwite/edit your files in-place instead of printing to standard output