I'm trying to remove all id=" "s from an .html file but I'm not sure where I am going wrong. I tried using regular expressions but all I am getting is the .html file rendering in my Ubuntu terminal.


grep -Ev '^$id\="[a-zA-Z][0-9]"' *.html

I am executing it with bash ex.sh.


3 Answers 3


Though this goes against my better judgment I'll post it (sed part).

That is: if it is for a quick and dirty fix go ahead. If it is a bit more serious or something you are going to do frequently etc. Use something else like python, perl etc. where you do not rely on regular expressions, but rather modules to handle HTML documents.

One of the simpler ways would be to use e.g. sed.

sed 's/\(<[^>]*\) \+id="[^"]*"\([^>]*>\)/\1\2/' sample.html > noid.html


            +--------------------------------- Match group 1
            |                      +---------- Match group 2
         ___|___                ___|___
        |       |              |       |  
sed 's/\(<[^>]*\) \+id="[^"]*"\([^>]*>\)/\1\2/' sample.html > noid.html
     |   |  | |   |  |    | ||    |  |      |
     |   |  | |   |  |    | ||    |  |      +- \1\2  Subst. with group 1 and 2
     |   |  | |   |  |    | ||    |  +-------- >     Closing bracket
     |   |  | |   |  |    | ||    +----------- [^>]* Same as below
     |   |  | |   |  |    | |+---------------- "     Followed by "
     |   |  | |   |  |    | +----------------- *     Zero or more times
     |   |  | |   |  |    +------------------- [^"]  Not double-quote
     |   |  | |   |  +------------------------ id="  Literal string
     |   |  | |   +---------------------------  \+   Space 1 or more times
     |   |  | +------------------------------- *     Zero or more times 
     |   |  +--------------------------------- [^>]  Not closing bracket
     |   +------------------------------------ <     Opening bracket
     +---------------------------------------- s     Substitute

Use sed -i to edit file in place. (Regrets possible but no undo.)

Better; example using perl:


use strict;
use warnings;

use HTML::TokeParser::Simple;
use HTML::Entities;
use utf8;

die "$0 [file]\n" unless defined $ARGV[0];

my $parser = HTML::TokeParser::Simple->new(file => $ARGV[0]);

if (!$parser) {
    die "No HTML file found.\n";

while (my $token = $parser->get_token) {
    print $token->as_is;

Your grep command would match nothing. But as you use the invert option -v it prints everything not matching – thus the entire file.

grep is not a in place file modifier but normally a tool for finding stuff in file(s). Try e.g.:

grep -o '\(<[^>]*\)id="[^"]*"[^>]*>' sample.html

-o means print only matching pattern. (Not whole line)

sed, awk etc. are often used to edit streams or files. E.g. as by example above.

From your grep there is a few miss-conceptions:


Would match exactly:

  1. id=
  2. One character in the range a-z or A-Z
  3. Followed by one single digit

In other words it would match:


Nothing like: id="foo99" or id="blah-gah".

Further it would match:

 ^ <-- start of line (As it is first in pattern or group)
 $ <-- end of line   (As you use the `-E` option)
 # Else it would be:
 ^ <-- start of line (As it is first in pattern or group)
 $ <-- dollar sign   (Does not mean end of line unless it is at end of
                      pattern or group)

Thus nothing.

  • 1
    man that's awesome! Apr 18, 2013 at 19:29
  • minor note: the sed example will only transform the first match on a line, add a /g on the end to transform all tags found in a single input line. If you have mixed case tags, add an i in there as well to be case-insensitive. (s/.../.../ig)
    – user54048
    Oct 20, 2018 at 18:01

I'm not seriously suggesting this, but I worked out how to do it with an XSLT processor that accepts html. Run with xsltproc --html strip-html-id.xslt input.html

<!-- strip-html-id.xslt -->

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="html" doctype-system="about:legacy-compat" />

  <xsl:template match="node()|@*">
      <xsl:apply-templates select="node()|@*"/>

  <xsl:template match="@id" />


As mentioned in another answer you can use a Ruby one-liner to parse HTML. For example, you can use the following:

ruby -rnokogiri -e 'doc = Nokogiri::HTML(readlines.join); doc.xpath("//@id").remove; puts doc' sample.html

This line parses the file given as argument, sample.html, strips it of all id attributes and prints the output. If sample.html is

<!DOCTYPE html>
    <h2 id="section1">Section 1</h2>
    <h2 id="section2">Section 3</h2>
    <h2>Section 4</h2>
    <h2 id="section5">Section 5</h2>

it outputs

<!DOCTYPE html>
    <h2>Section 1</h2>
    <h2>Section 3</h2>
    <h2>Section 4</h2>
    <h2>Section 5</h2>

Note that by using Nokogiri::HTML() will put the content inside html and body if it is not already in such a structure and it will also add a DOCTYPE. If you want to strip html, body and DOCTYPE or do not want them added you can use

ruby -rnokogiri -e 'doc = Nokogiri::HTML.fragment(readlines.join); doc.search("@id").remove; puts doc' sample.html

which for the same input file will output

    <h2>Section 1</h2>
    <h2>Section 3</h2>
    <h2>Section 4</h2>
    <h2>Section 5</h2>
  • Is there a bug in that? It strips of DOCTYPE, head etc. and put it all in body tag. It also reformats document.
    – Runium
    Apr 18, 2013 at 20:28
  • @Sukminder I made an edit shortly after I posted. Now it does not wrap it in anything.
    – N.N.
    Apr 19, 2013 at 5:02
  • Thanks for feedback, but it is with your current line. Spec: ruby 1.9.3p194 (2012-04-20 revision 35410) [i686-linux], Nokogiri (1.5.5). Ran it on the HTML for this site. (As in this: unix.stackexchange.com/questions/72917/…)
    – Runium
    Apr 19, 2013 at 14:22
  • @Sukminder I have edited to show the difference of parse and fragment.
    – N.N.
    Apr 19, 2013 at 14:42
  • No. If the <body> tags are in column 1 (no space before it on the line) – it is not stripped using fragment. If there is a space or a tab etc. in front of it then it is. It also moves such things as meta, title, link to css and javascript down to body when not stripped. Here is a sample.
    – Runium
    Apr 19, 2013 at 15:24

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.