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


12

考虑一个文本文件users.txt

#alice
#bob
charlie
dotan
eric

我需要注释所有内容(从(独占)最后一个注释行到(包括))dotan。结果如下:

#alice
#bob
#charlie
#dotan
eric

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

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

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

然后,我添加一个并用注释sed

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

我知道我很聪明,可以将所有这些与一些bc丑陋的东西放在一起。当然必须有一种更清洁的方法吗?

Answers:


5

怎么样

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

7

如果现有的注释行形成单个连续的块,则可以从第一条注释行开始匹配,仅注释掉直到并包括尚未注释的结束模式的那些行

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

如果现有注释不连续,则由于sed范围匹配的贪婪性质,我认为您需要执行以下操作

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

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


4

您可以通过一次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旧缓冲区,e x更改缓冲区,然后用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的所有行,而其他行则保持不变。
当然,这是假设在match之前总是至少有一条注释行PATTERN。如果不是这种情况,您可以在替换之前添加其他支票:/^#/{s/\n/&#/g}


谢谢,我将从这个答案中学到很多东西!
dotancohen

等一下,我一定搞砸了。这与最后几行评论无关吗?不,我明白了,是的。最后一个系列+ dotan。该死的聪明。
mikeserv

1
您总是会找到最好的问题。该死的多坦把我扔了一段时间-也许还是,我还没有测试过。谢谢,唐。
mikeserv

2

这是另一个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并将整个缓冲区分支到est以进行打印,否则它将使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在OOK sed的模式空间,因为它的工作原理我们可以得到的幕后发生的事情更好的主意,并更好地理解如何指导其工作。

在这种情况下,我们可以观察sed堆栈输入,直到找到第二次出现的\n#.*\ndotanin输入,以及当它一次开始打印前一行时为止。挺酷的 我学到了很多工作。


很好谢谢!最后一段的解释很棒,我也会花很多时间从这篇文章中学习。不错的堆栈!
dotancohen

1
@dotancohen-这是一个非常好的问题。看一下编辑以查看堆栈
mikeserv

2
我在编辑历史记录中注意到该条目Handle many dotans。我确定这是我妻子最糟糕的噩梦。
dotancohen

1
@dotancohen-是的,这很艰难。#\ndotan\ndotan这些东西很难做到。当我说这是一个好问题时,我是认真的。我认为我已经达到了完美的水平,但是您可能会遇到的一个问题是,如果注释块之间的间隔为1000行-这会使它变慢。例如s/\n/&/150;t/\n#如果缓冲区跨越150行,您可能会先插入类似in的东西来打破缓冲区。反正,也许这正是她一直在等待所有沿
mikeserv
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.