【问题标题】:Sed range and removing last matching lineSed 范围和删除最后一个匹配行
【发布时间】:2018-06-07 16:41:25
【问题描述】:

我有这些数据:

One
  two
  three
Four
  five
  six
Seven
  eight

还有这个命令:

sed -n '/^Four$/,/^[^[:blank:]]/p'

我得到以下输出:

Four
  five
  six
Seven

如何更改此 sed 表达式,使其与输出的最后一行不匹配?所以理想的输出应该是:

Four
  five
  six

我尝试了很多涉及感叹号的事情,但还没有成功。

【问题讨论】:

    标签: bash shell sed


    【解决方案1】:

    使用“do..while()”循环:

    sed -n '/^Four$/{:a;p;n;/^[[:blank:]]/ba}'
    

    详情:

    /^Four$/ {
        :a         # define the label "a"
        p          # print the pattern-space
        n          # load the next line in the pattern space
        /^[[:blank:]]/ba # if the pattern succeeds, go to label "a"
    }
    

    【讨论】:

    • 这个答案很漂亮。谢谢你的解释!
    【解决方案2】:

    您可以通过管道连接到另一个 sed 并跳过最后一行:

    sed -n '/^Four$/,/^[^[:blank:]]/p' file | sed '$d'
    

    Four
      five
      six
    

    您也可以使用:

    sed -n '/^Four$/,/^[^[:blank:]]/{/^Four$/p; /^[^[:blank:]]/!p;}' file
    

    【讨论】:

      【解决方案3】:

      您使用了错误的工具。 sed 用于做 s/old/new,仅此而已。只需使用 awk:

      $ awk '/^[^[:blank:]]/{f=/^Four$/} f' file
      Four
        five
        six
      

      它是如何工作的:每次它找到一个不以空格 (/^[^[:blank:]]/) 开头的行时,如果该行以 Four 和 0 开头,它会将标志 f(用于“找到”)设置为 1否则(f=/^Four$/)。每当f 为非零时,即被解释为真实条件,因此调用 awks 的默认行为,即打印当前行。因此,当它遇到以 4 开头的块时,它会打印该块中的每一行,因为 f 是 1/true,而对于每个其他块,它不会打印,因为 f 是 0/false。

      【讨论】:

      • 您能再解释一下吗?非常有兴趣了解这是如何工作的
      • 我在答案中添加了解释。
      【解决方案4】:

      关注awk 可能会对您有所帮助。

      awk '!/^ /{flag=""} /Four/{flag=1} flag'   Input_file
      

      输出如下。

      Four
        five
        six
      

      如果您需要将输出保存到 Input_file 本身,请将> temp_file && mv temp_file Input_file 添加到上述代码中。

      【讨论】:

        【解决方案5】:
        grep -Pzo '\n\KFour\n(\s.+\n)+' input.txt
        

        输出

        Four
          five
          six
        

        【讨论】:

          【解决方案6】:

          这可能对你有用(GNU sed):

          sed '/^Four/{:a;n;/^\s/ba};d' file
          

          如果该行以Four 开头,则打印它以及任何以空格开头的行。

          另一种方式:

          sed '/^\S/h;G;/^Four/MP;d' file
          

          如果一行以非空格开头,请将其复制到保留空间 (HS)。将 HS 附加到每一行,如果任一行以 Four 开头,则打印第一行并删除其余行。这将删除除以Four 开头的部分以外的所有行。

          【讨论】:

            最近更新 更多