使用 sed 将字符串附加到模式的第四次出现 [英] Using sed to append a string to the fourth occurrence of a pattern

查看:44
本文介绍了使用 sed 将字符串附加到模式的第四次出现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<div class="body"><div class="detail-list-item"><!-- 这里有一些内容-->

<div class="detail-list-item"><!-- 这里还有一些内容-->

<div class="detail-list-item"><!-- 这里还有一些内容-->

<div class="detail-list-item"><!-- 这里还有一些内容-->

<div class="detail-list-item last-item"><!-- 这里的一些最终内容-->

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

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

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

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

<div class="body"><div class="detail-list-item"><!-- 这里有一些内容-->

<div class="detail-list-item"><!-- 这里还有一些内容-->

<div class="detail-list-item"><!-- 这里还有一些内容-->

<div class="detail-list-item last-item"><!-- 这里的一些最终内容--><!-- 注意我们是如何缩短一个 div 并且这个 div 的类有第二个类 -->

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

解决方案

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

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

解释如下:

# options: -r 扩展正则表达式,所以括号不需要转义# -n 不自动打印模式空间# -i 就地编辑文件H;# 将当前行添加到保持空间$ # 如果我们在最后一行{ # 直到 '}' 的命令仅在最后一行时运行X;# 交换模式空间和保持空间s/# 搜索/替换\n(.*list-item) # 贪婪匹配最后一个'list-item',放入第1组(".*) #双引号必须跟在'list-item'之后,匹配尽可能多的# 尽可能多的字符并放入第 2 组\n 

# 匹配所有下一个(最终)双缩进# div,不要放在一个组中/\1 last-item\2 # 在组 1 和组 2 之前插入 'last-item',final# 双缩进的 div 将被删除/p # 打印结果}

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

sed -i '/

/d'/path/to/file

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

I'm developing a bash patch to perform multiple operations on plain text files to help reduce manual edits on multiple web servers. One part that is beyond the scope of my sed knowledge is how I would go about editing a string that occurs more than once, only editing one of the specific occurrences. Take the following redacted HTML for example:

<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>

I need to rid of the last block of code, and while not ideal given that this file may change in future updates, I'm using the following command to delete the content by lines

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

Where 29 is the line that <div class="detail-list-item last-item"> is on, and 33 is it's corresponding closing </div> tag. Is there a better way to do this to prevent future updated versions of this file so that I won't have to check the file to make sure I'm not deleting the wrong lines?

The final piece is that I need to replace the previous html class to include last-item as a second class. So the final html will resemble:

<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>

What sed command(s) can accomplish this task?

解决方案

Since sed processes the file line by line, it might not be the best solution for this. However since your file is pretty small, you can use this somewhat hacky solution which puts the entire file into the hold buffer, and then performs a substitution on the entire file at once:

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

Here is an explanation:

# 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
  }

You could do the part where you delete the final div with a much simpler command:

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

Unfortunately I am not aware of a simple way to add last-item as a second class to the final div.

这篇关于使用 sed 将字符串附加到模式的第四次出现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆