1

I want to refine an HTML code using sed, as an extra refinement procedure after refining it using HTML Tidy, as HTML Tidy doesn’t look flexible enough for some requirements.

I used this command to add some tabs and/or line breaks to some tags and remove them from others:

s/<li>/\t&/g
s/\n<\/li>/<\/li>/g
  1. The first command worked fine unless li has an attribute, so, how can I target an opening tag regardless of whether it has an attribute or not?
  2. The second command didn’t work at all. I want here to put the closing tag </li> at the end of the previous line.
  • 1
    \r is carriage return. \n is line-feed. Which line-ending do you have in your file? You say \r but then use \n in the sed. – meuh May 25 '16 at 18:03
  • Well, it was my fault, I’m sorry; I was applying HTML Tidy and sed respectively from the same input to the same output :) I changed the question now. – Anas R. May 26 '16 at 0:15
  • @don_crissti exactly. – Anas R. May 26 '16 at 0:16
  • @AnasR. Is this linux or OSX? It makes a difference. – John1024 May 26 '16 at 0:19
  • @John1024 Linux. – Anas R. May 26 '16 at 0:20
0

Consider this sample file:

$ cat sample.html 
<li a=x>Point One
</li>
<li>Point Two
</li>

I believe that this sed command does what you ask (this may require GNU sed):

$ sed -Ez 's|<li\b|\t<li|g; s|\n</li\b|</li|g' sample.html
        <li a=x>Point One</li>
        <li>Point Two</li>

How it works

  • -E

    Use extended regex.

  • -z

    Read nul-delimited data. Since a proper html file has not nul-characters, this has the effect of reading in the whole file at once.

  • s|<li\b|\t<li|g

    This puts a tab in front of every occurrence of <li followed by a word boundary.

  • s|\n</li\b|</li|g

    This replaces every occurrence of newline followed by <li followed by a word boundary with <li.

A variation: putting <li> on its own line

$ sed -Ez 's|<li[^>]*>|&\n|g; s|\n</li\b|</li|g' sample.html
<li a=x>
Point One</li>
<li>
Point Two</li>

Obligatory warning

html can be complex and these sed commands are only intended to work on simple cases.

  • Great, thank you so much. I am still new here to vote up your answer :) – Anas R. May 26 '16 at 11:54
  • It seems it doesn't target the whole opening tag. Suppose we want to add a line break after the opening tag, I tried s/<li\b>/<li\b>\n/g and s/<li\b>/\n&\n/g, but didn't work. – Anas R. May 26 '16 at 12:26
  • @AnasR. OK. I added code for that. – John1024 May 26 '16 at 17:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.