从sed/START /,/ END /中排除第一行和最后一行

Che*_*evy 44 unix scripting sed text-manipulation

考虑输入:

=sec1=
some-line
some-other-line

foo
bar=baz

=sec2=
c=baz
Run Code Online (Sandbox Code Playgroud)

如果我只想处理= sec1 =我可以通过以下方式注释掉该部分:

sed -e '/=sec1=/,/=[a-z]*=/s:^:#:' < input
Run Code Online (Sandbox Code Playgroud)

......好吧,差不多.

这将注释包括 "= sec1 ="和"= sec2 ="行的行,结果将类似于:

#=sec1=
#some-line
#some-other-line
#
#foo
#bar=baz
#
#=sec2=
c=baz
Run Code Online (Sandbox Code Playgroud)

我的问题是:在sed中从/ START /,/ END /范围中排除开始和结束行的最简单方法什么

我知道在很多情况下,"s :::"爪子的细化可以在这种特定情况下给出解决方案,但我在这里遵循通用解决方案.

在" Sed - An Introduction and Tutorial "中,Bruce Barnett写道:"我稍后会告诉你如何限制命令,但不包括包含指定模式的行."但是我无法找到他实际显示的位置这个.

在由Eric Pement编写的" 有用的SED单行文章"中,我只能找到包容性的例子:

# print section of file between two regular expressions (inclusive)
sed -n '/Iowa/,/Montana/p'             # case sensitive
Run Code Online (Sandbox Code Playgroud)

Vil*_*ari 38

这应该做的伎俩:

sed -e '/=sec1=/,/=sec2=/ { /=sec1=/b; /=sec2=/b; s/^/#/ }' < input
Run Code Online (Sandbox Code Playgroud)

这包含在sec1和sec2之间,然后用b命令跳过第一行和最后一行.这将在sec1和sec2之间留下所需的行(不包括),并且该s命令会添加注释符号.

不幸的是,您需要重复使用正则表达式来匹配分隔符.据我所知,没有比这更好的方法了.至少你可以保持正则表达式清洁,即使它们被使用了两次.

这是根据SED FAQ改编的:如何处理RE1和RE2之间的所有线路,不包括线路本身?

  • 不确定其他版本,但使用GNU sed,这可以使用`'/ = sec1 = /,/ = sec2 =/{//轻松完成!s/^ /#/}'`来自[手册](https://www.gnu.org/software/sed/manual/sed.html#Regexp-Addresses)`空正则表达式'//'重复最后一个正则表达式匹配 (6认同)

Pau*_*ker 13

如果你对范围之外的线路不感兴趣,但只是想从问题(这就是我带到这里)的爱荷华州/蒙大拿州的非包容性变体,你可以写"除了第一个和最后一个匹配行"子句很容易与第二个sed:

sed -n '/PATTERN1/,/PATTERN2/p' < input | sed '1d;$d'

就个人而言,我发现这比同等的更清晰(虽然在大文件上比较慢)

sed -n '1,/PATTERN1/d;/PATTERN2/q;p' < input

  • 我有预感,如果流/文件中有多个范围,它们就不相同. (3认同)

Mik*_*lVS 7

另一种方式是

sed '/begin/,/end/ {
       /begin/n
       /end/ !p
     }'
Run Code Online (Sandbox Code Playgroud)

/begin/n- >跳过具有"开始"模式的行
/end/ !p- >打印所有没有"结束"模式的行

取自Bruce Barnett的sed教程http://www.grymoire.com/Unix/Sed.html#toc-uh-35a