使用sed将字符串附加到模式的第四个匹配项

时间:2012-02-16 17:24:42

标签: sed

我正在开发一个bash补丁来对纯文本文件执行多项操作,以帮助减少多个Web服务器上的手动编辑。超出我的sed知识范围的一部分是如何编辑多次出现的字符串,仅编辑其中一个特定事件。以下面的编辑HTML为例:

<div class="dashlet">
  <div class="body">
    <div class="detail-list-item">
      <!-- some content here -->
    </div>
    <div class="detail-list-item">
      <!-- some more content here -->
    </div>
    <div class="detail-list-item">
      <!-- some more content here -->
    </div>
    <div class="detail-list-item">
      <!-- some more content here -->
    </div>
    <div class="detail-list-item last-item">
      <!-- some final content here -->
    </div>
  </div>
</div>

我需要摆脱最后一段代码,虽然不太理想,因为这个文件可能会在将来的更新中发生变化,但我使用以下命令按行删除内容

sed -i '29,33d' /path/to/file

其中29是<div class="detail-list-item last-item">所在的行,33是相应的结束</div>标记。有没有更好的方法来防止此文件的未来更新版本,以便我不必检查文件以确保我没有删除错误的行?

最后一部分是我需要替换以前的html类以包含last-item作为第二类。所以最终的html将类似于:

<div class="dashlet">
  <div class="body">
    <div class="detail-list-item">
      <!-- some content here -->
    </div>
    <div class="detail-list-item">
      <!-- some more content here -->
    </div>
    <div class="detail-list-item">
      <!-- some more content here -->
    </div>
    <div class="detail-list-item last-item">
      <!-- some final content here -->
      <!-- note how we are one div shorter and this div's class has a second class -->
    </div>
  </div>
</div>

什么sed命令可以完成这项任务?

1 个答案:

答案 0 :(得分:2)

由于sed逐行处理文件,因此它可能不是最佳解决方案。但是,由于您的文件非常小,您可以使用这种有点hacky的解决方案,将整个文件放入保留缓冲区,然后立即对整个文件执行替换:

sed -rni 'H;${x;s/\n(.*list-item)(".*)\n    <div.*    <\/div>/\1 last-item\2/p}' /path/to/file

以下是解释:

# options: -r  extended regex so parentheses don't need to be escaped
#          -n  don't automatically print pattern space
#          -i  edit file in place
H;                     # add the current line to the hold space
$                      # if we are at the last line
  {                    # commands until '}' are only run if at the last line
    x;                 # swap pattern space and hold space
    s/                 # search/replace
      \n(.*list-item)  # greedy match to the last 'list-item', put in group 1
      (".*)            # double quote must follow 'list-item', match as many
                       # characters as possible and put in group 2
      \n    <div.*    <\/div>    # match all of the next (final) double-indented
                                 # div, don't put it in a group
     /
      \1 last-item\2   # insert ' last-item' before groups 1 and 2, final 
                       # double-indented div will be deleted
     /p                # print the result
  }

您可以使用更简单的命令执行删除最终div的部分:

sed -i '/<div.*last-item/,/<\/div>/d' /path/to/file

不幸的是,我不知道将last-item作为第二个类添加到最后一个div的简单方法。