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

gwo2fgha  于 2023-10-18  发布在  Unix
关注(0)|答案(6)|浏览(159)

考虑输入:

=sec1=
some-line
some-other-line

foo
bar=baz

=sec2=
c=baz

例如,如果我只想处理= sec 1 =,我可以通过以下方式注解掉该部分:

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

差不多了
这将注解行 *,包括 *“= sec 1 =”和“= sec 2 =”行,结果如下:

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

我的问题是:在sed中,从/START/,/END/范围中排除起始行和结束行的最简单方法是什么?
我知道在很多情况下,“s:“claws的细化可以在这个特定的情况下给出给予解决方案,但我在这里追求的是通用的解决方案。
在“塞德-一个介绍和介绍”布鲁斯巴内特写道:“我稍后将向您展示如何限制命令,但不包括包含指定模式的行。",但我无法找到他实际显示这一点的地方。
在Eric Pement编译的“USEFUL ONE-LINE SCRIPTS FOR SED“中,我只能找到包含的例子:

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

mitkmikd1#

这应该可以解决问题:

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

这将在sec1和sec2之间进行匹配,然后使用b命令跳过第一行和最后一行。这将在sec1和sec2之间留下所需的行(不含),s命令将添加注解符号。
不幸的是,您确实需要重复正则表达式来匹配分隔符。据我所知,没有更好的办法了。至少你可以保持正则表达式干净,即使它们被使用了两次。
这是改编自SED FAQ:如何对RE1和RE2之间的所有线路进行寻址,不包括线路本身?

2izufjch

2izufjch2#

如果你对范围之外的行不感兴趣,而只是想从问题中得到爱荷华州/蒙大拿州示例的非包含变体(这就是我来到这里的原因),你可以用第二个sed很容易地编写“except for the first and last matching lines”子句:
sed -n '/PATTERN1/,/PATTERN2/p' < input | sed '1d;$d'
就我个人而言,我觉得这比同等的方法稍微清楚一些(尽管在大文件上慢一些
sed -n '1,/PATTERN1/d;/PATTERN2/q;p' < input

n7taea2i

n7taea2i3#

另一种方式是

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

/begin/n->跳过具有“开始”模式的行
/end/ !p->打印所有没有“结束”模式的行
摘自布鲁斯巴内特的sed教程http://www.grymoire.com/Unix/Sed.html#toc-uh-35a

drkbr07n

drkbr07n4#

我用过:

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

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

gr8qqesn

gr8qqesn5#

也可以使用awk

awk '/sec1/{f=1;print;next}f && !/sec2/{ $0="#"$0}/sec2/{f=0}1' file
p8h8hvxi

p8h8hvxi6#

你不需要重复任何正则表达式就可以做到这一点。

$ sed -e '/^=sec1=$/{:0;n;/^=\w*=$/!{s/^/#/;b0}}' <<EOF
=sec1=
some-line
some-other-line

foo
bar=baz

=sec2=
c=baz
EOF

输出将为:

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

拆开sed脚本,我们有:

  1. /^=sec1=$/匹配开头部分标记的正则表达式地址
  2. {:0;n;/^=\w*=$/!{s/^/#/;b0}}命令块,如下所示:
  3. :0稍后返回的标签
  4. n打印当前行,并读取下一行
  5. /^=\w*=$/!正则表达式地址匹配任何不是节标记的行
  6. {s/^/#/;b0}命令块,如下所示:
  7. s/^/#/#前置到该行
  8. b0分支到标签0
    :0b0之间的内部循环将继续循环,直到遇到任何作为节标记(或文件结尾)的行。

相关问题