47

考虑输入:

=sec1=
some-line
some-other-line

foo
bar=baz

=sec2=
c=baz

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

sed -e '/=sec1=/,/=[a-z]*=/s:^:#:' < input

……嗯,差不多。

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

#=sec1=
#some-line
#some-other-line
#
#foo
#bar=baz
#
#=sec2=
c=baz

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

我知道在许多情况下,“s:::”爪的改进可以在这种特定情况下给出解决方案,但我在这里寻求通用解决方案。

在“ Sed - 简介和教程”中,布鲁斯·巴内特写道:“稍后我将向您展示如何将命令限制在但不包括包含指定模式的行。”,但我无法找到他实际显示的位置这个。

在 Eric Pement 编译的“ USEFUL ONE-LINE SCRIPTS FOR SED ”中,我只能找到包含性的示例:

# print section of file between two regular expressions (inclusive)
sed -n '/Iowa/,/Montana/p'             # case sensitive
4

5 回答 5

40

This should do the trick:

sed -e '/=sec1=/,/=sec2=/ { /=sec1=/b; /=sec2=/b; s/^/#/ }' < input

This matches between sec1 and sec2 inclusively and then just skips the first and last line with the b command. This leaves the desired lines between sec1 and sec2 (exclusive), and the s command adds the comment sign.

Unfortunately, you do need to repeat the regexps for matching the delimiters. As far as I know there's no better way to do this. At least you can keep the regexps clean, even though they're used twice.

This is adapted from the SED FAQ: How do I address all the lines between RE1 and RE2, excluding the lines themselves?

于 2009-07-27T10:38:50.007 回答
14

如果您对范围之外的行不感兴趣,而只是想要问题中的爱荷华州/蒙大拿州示例的非包容性变体(这就是让我来到这里的原因),您可以编写“除了第一个和最后一个使用第二个 sed 轻松匹配行”子句:

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

就个人而言,我发现这比同等文件更清晰(尽管在大文件上速度较慢)

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

于 2011-03-07T10:48:23.677 回答
7

另一种方法是

sed '/begin/,/end/ {
       /begin/n
       /end/ !p
     }'

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

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

于 2012-07-12T11:10:54.067 回答
2

我用过:

sed '/begin/,/end/{/begin\|end/!p}'

这将搜索模式之间的所有行,然后打印不包含模式的所有内容

于 2017-08-15T14:15:32.297 回答
1

你也可以使用 awk

awk '/sec1/{f=1;print;next}f && !/sec2/{ $0="#"$0}/sec2/{f=0}1' file
于 2009-07-27T10:53:43.503 回答