【问题标题】:sed print between two line patterns only if both patterns are foundsed 仅在找到两种线型时才在两种线型之间打印
【发布时间】:2016-02-27 03:38:43
【问题描述】:

假设我有一个文件:

Line 1
Line 2
Start Line 3
Line 4 
Line 5
Line 6
End  Line 7
Line 8
Line 9
Start Line 10
Line 11
End Line 12
Line 13
Start line 14
Line 15

只有在找到 /Start//End/ 时,我才想使用 sed 在模式之间打印。

sed -n '/Start/,/End/p' 如果您知道两个标记都在那里并且按照预期的顺序工作,那么它会按预期工作,但如果End 出现故障或不存在,它只会从Start 打印到文件末尾。 (即在示例中打印第 14 行和第 15 行)

我试过了:

sed -n '/Start/,/End/{H;}; /End/{x; p;}' file

打印:

# blank line here...
Start Line 3
Line 4 
Line 5
Line 6
End  Line 7
End  Line 7
Start Line 10
Line 11
End Line 12

这很接近,但有两个问题:

  1. 不需要的前导空白行
  2. 第 7 行结束打印两次

我希望得到类似的结果

$ awk '/Start/{x=1} x{buf=buf$0"\n"} /End/{print buf; buf=""; x=0}' file
Start Line 3
Line 4 
Line 5
Line 6
End  Line 7

Start Line 10
Line 11
End Line 12

(块之间不需要空行...)

【问题讨论】:

  • 块内是否允许另一个“起始行”? (比如第5行是起始行,你要3-7块还是5-7块?)
  • @CasimiretHippolyte:好问题。不,它不需要处理重叠或嵌套的/Start/ 块。只需处理(通过不打印)缺少/End/
  • 所以答案是第 5-7 块?
  • 只是好奇 - 因为这可以在 awk 中简单、稳健且可移植地完成,而且您已经知道如何在 awk 中完成,为什么还要寻找 sed 解决方案?
  • GNU awk 具有捕获组,但它们只是一种方便,您可以使用 POSIX awk 获得必要的行为,它可能需要您编写更多代码。在使用 sed 30 多年和使用 awk 20 多年之后,我的建议是您使用 sed 进行单行的简单替换,而使用 awk 进行其他所有操作。即使简单内容的 awk 代码最终会稍微不那么简短,但至少您正在学习如何在需要处理复杂内容时使用 awk!如果您愿意发布它,我很想看看您在新问题中提到的更完整的示例。

标签: bash sed


【解决方案1】:

使用 GNU sed 和 Solaris 11 中的 sed:

sed -n '/Start/{h;b;};H;/End/{g;p;}' file

输出:

开始线 3 4号线 5号线 6号线 结束第 7 行 开始 10 号线 11号线 结束第 12 行

如果找到Start 复制 当前模式空间以保存空间 (h) 并跳转到脚本末尾 (b)。每隔一行 追加 当前模式空间以保留空间 (H)。如果找到End,则将保留空间复制回模式空间(g),然后打印模式空间(p)。

【讨论】:

  • 如果我在b 分支到最后放置一个CR,这适用于OS X。谢谢!
  • 也许这适用于 OS X:sed -n -e '/Start/{h;b' -e '};H;/End/{g;p;}' file
【解决方案2】:

GNU sed:遇到Start 后,只要我们没有看到End,就继续追加行;完成后,打印模式空间并重新开始:

$ sed -n '/Start/{:a;N;/End/!ba;p}' infile
Start Line 3
Line 4 
Line 5
Line 6
End  Line 7
Start Line 10
Line 11
End Line 12

在块之间获取换行符很棘手。这会在每个块之后添加一个,但最后会产生一个额外的空白:

$ sed -n '/Start/{:a;N;/End/!ba;s/$/\n/p}' infile
Start Line 3
Line 4 
Line 5
Line 6
End  Line 7

Start Line 10
Line 11
End Line 12
[blank]

【讨论】:

  • 在 OS X 上我得到unexpected EOF (pending }'s)
  • @dawg 嗯,尝试在p 之后添加;,或者实际输入换行符而不是分号,这样行吗?
  • OSX sed 对此很讨厌。以前有一些技巧可以使这项工作成功,但我忘记了
  • 在 OSX 上这个sed 命令可以工作:sed -n -e '/Start/{:a;' -e 'N;/End/!ba;' -e 'p;}' file
【解决方案3】:

你可以使用这个 awk:

awk 'x{buf=buf ORS $0} /Start/{x=1; buf=$0} /End/{print buf; buf=""; x=0}' file

Start Line 3
Line 4
Line 5
Line 6
End  Line 7
Start Line 10
Line 11
End Line 12

这是在 OSX (BSD) sed (Based on Benjamin's sed command) 上执行相同操作的 sed 版本:

sed -n -e '/Start/{:a;' -e 'N;/End/!ba;' -e 'p;}' file

【讨论】:

  • 我知道我可以使用awkPerl。我正在尝试使用sed 进行复制。
  • 我们不得不在 OS X 上分解命令有多烦人。从功能上讲,sed -e 'something' -e 'more' 是在产生 sed -e 'something\nmore 吗?
  • 确实很烦人。我们在 sed 中有标签的地方,它需要在一个单独的 -e 部分中
【解决方案4】:

就个人而言,我更喜欢你的 awk 解决方案,但是:

  sed -n -e '/start/,/end/H' -e '/end/{s/.*//; x; p}' input

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多