Using sed to append a line to the fourth occurrence of a pattern

I am developing a bash patch to do multiple text file operations to reduce manual changes across multiple web servers. One part that is beyond my knowledge is how I was going to edit a line that occurs more than once, only by editing one of the specific cases. Take the following edited 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 get rid of the last block of code, and while it is not ideal, if this file might change in future updates, I use the following command to remove content line by line

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

      

Where 29 is the line in which it is <div class="detail-list-item last-item">

included and 33 is the corresponding end tag </div>

. Is there a better way to do this to prevent future updated versions of this file so that I don't have to check the file to make sure I'm not deleting the wrong lines?

The last part is that I need to replace the previous html class to include last-item

as a second class. Thus, 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 class has a second class -->
    </div>
  </div>
</div>

      

What sed commands can accomplish this task?

+1


source to share


1 answer


Since sed processes the file line by line, this may not be the best solution for this. However, since your file is quite small, you can use this somewhat hacky solution, which puts the entire file in the storage buffer and then substitutes 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's 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 can do the part where you remove the final div with a much simpler command:

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

      

Unfortunately I don't know of an easy way to add last-item

as a second class to the final div.

+2


source







All Articles