注释从最后注释行到带有“foo”的行的所有行

注释从最后注释行到带有“foo”的行的所有行

考虑一个文本文件users.txt

#alice
#bob
charlie
dotan
eric

我需要注释从(不包括)最后一个注释行到(包括)的所有内容dotan。这是结果:

#alice
#bob
#charlie
#dotan
eric

有没有一个好的sedoneliner 可以做到这一点?我会对任何工具感到满意,不仅仅是sed,真的。

目前我正在获取最后注释行的行号,如下所示:

$ cat -n users.txt | grep '#' | tail -n1
  2 #bob

然后我添加一个并评论sed

$ sed -i'' '3,/dotan/ s/^/#/' users.txt

我知道我可以聪明点,把这一切和一些东西放在一起,bc写成一句丑陋的俏皮话。当然必须有一种更清洁的方法吗?

答案1

如果现有的注释行形成一个连续的块,那么您可以从第一的相反,注释行,仅注释掉那些直到并包括尚未注释的结束模式的行

sed '/^#/,/dotan/ s/^[^#]/#&/' file

如果现有注释不连续,那么由于 sed 范围匹配的贪婪本质,我认为您需要执行类似的操作

tac file | sed '/dotan/,/^#/ s/^[^#]/#&/' | tac

即匹配向上从结束模式到“第一个”注释 - 显然,如果您想要一个就地解决方案,那么这不是那么方便。

答案2

怎么样

perl -pe '$n=1 if s/^dotan/#$&/; s/^[^#]/#$&/ unless $n==1;' file

或者,在 awk 中也有同样的想法:

awk '(/^dotan/){a=1; sub(/^/,"#",$1)} (a!=1 && $1!~/^#/){sub(/^/,"#",$1);}1; ' file

答案3

您可以通过一次调用来处理这两种情况(单个连续块中的注释行或散布在未注释行之间)sed

sed '1,/PATTERN/{/^#/{x;1d;b};//!{H;/PATTERN/!{1h;d};//{x;s/\n/&#/g}}}' infile

这仅处理范围内的行1,/PATTERN/。它x改变了保持空间w。每次注释一行时都会使用模式空间(因此保留缓冲区中永远不会有超过一个注释行)并将未注释的每一行附加到H旧空间(当在第一行时,1d和 分别1h还需要删除初始行)保持缓冲区中的空行)。
当它到达与 PATTERN 匹配的行时,它还将其附加到H旧缓冲区,ex更改缓冲区,然后用ewline 和 a替换\n模式空间中的每个 ewline 字符(也就是说,模式空间中的所有行现在都以,包括第一行作为保留空间中的第一行始终是注释行)。 有样品:\n##
infile

alice
#bob
bill
#charlie
ding
dong
dotan
jimmy
#garry

跑步:

sed '1,/dotan/{                   # if line is in this range    -start c1
/^#/{                             # if line is commented        -start c2
x                                 # exchage hold space w. pattern space
1d                                # if 1st line, delete pattern space
b                                 # branch to end of script
}                                 #                             -end c2
//!{                              # if line is not commented    -start c3
H                                 # append to hold space
/dotan/!{                         # if line doesn't match dotan -start c4
1h                                # if 1st line, overwrite hold space
d                                 # delete pattern space
}                                 #                             -end c4
//{                               # if line matches dotan       -start c5
x                                 # exchage hold space w. pattern space
s/\n/&#/g                         # add # after each newline character
}                                 #                             -end c5
}                                 #                             -end c3
}' infile                         #                             -end c1

输出:

alice
#bob
bill
#charlie
#ding
#dong
#dotan
jimmy
#garry

因此它只注释从(并排除)#charlie到(并包括)的行dotan,而其他行保持不变。
当然,这假设在匹配的行之前始终至少有一个注释行PATTERN。如果不是这种情况,您可以在更换之前添加额外的检查:/^#/{s/\n/&#/g}

答案4

这是另一个sed

sed  -e:n -e'/\n#.*\ndotan/!{$!{N;/^#/bn'      \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g' \
-et  -e\} -eP\;D <in >out

这正如你所要求的那样。它仅在堆栈上工作 - 在必要时构建它,并在注释行出现之间持续必要的时间,并在找到注释行时转储旧缓冲区以支持输入中的新注释行。图片...

在此输入图像描述

抱歉,我不知道我为什么这么做。但我想到了。

无论如何,sed在任何系列中的每个最后注释行之间分布其缓冲区,永远不会在缓冲区中保留比准确跟踪最后注释事件所需的更多的内容,并且如果在任何时候遇到最后一行,那么它将尝试最终的g局部执行语句并分支t将整个缓冲区打印出来,否则它将P立即打印从缓冲区中释放的所有行。

我想这就是让我想起手风琴的原因......

printf %s\\n   \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric |
sed  -e:n -e'l;/\n#.*\ndotan/!{$!{N;/^#/bn'     \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g'  \
-et  -e\} -eP\;D

#alice
#alice\n#bob$
#alice\n#bob\ncharlie$
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob
#charlie
#dotan
eric

这个命令和上面的命令只有一处不同,那就是l顶部的 ook 命令。当我们l观察sed的模式空间的工作原理时,我们可以更好地了解幕后发生的事情,并更好地理解如何指导其工作。

在这种情况下,我们可以观察sed堆栈输入,直到找到第二次出现的\n#.*\ndotan输入,并且当它开始一次一行打印前一个输入时。有点酷。我在这方面学到了很多东西。

相关内容