 <p>I think your current regexp isn't working because it's matching the entire line. Just eyeballing it, it looks like you're matching the opening string "<code>&lt;input</code>" then as many characters as you can, with the final character being something other than a <code>/</code>, and then the closing <code>&gt;</code>.</p> <p>In the case of <code>&lt;input type='submit' value='Save' /&gt;&lt;/td&gt;&lt;/tr&gt;</code> since it's greedy, it'll run all the way to the last <code>&gt;</code> that works. Which happens to be the <code>&gt;</code> for the <code>td</code> (since your grep finishes with a <code>.</code>) </p> <p>As a bit of a hack-y replacement (I'm sure there's a more elegant way to do this..):</p> <pre><code>grep -P -o "&lt;input.*?(?&lt;=( .)|([^/]))&gt;" test.html </code></pre> <p>(grep 2.6.3/cygwin if that's of relevance)</p> <p>which roughly translates: get me anything starting with "<code>&lt;input</code>", then ending with "<code>&gt;</code>" (lazily), then look back and check that either that the 2nd last character before the closing <code>&gt;</code> isn't a space, or that the last character isn't a close slash.</p> <p>if test.html has (for argument's sake):</p> <pre><code>&lt;input type='submit' value='Save' /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;input type="text" name="name" id="name"/&gt; &lt;input type='submit' value='Save'&gt; &lt;a&gt;&lt;input type="blah" /&gt;&lt;/a&gt; &lt;input/&gt; &lt;input&gt;&lt;/i&gt; </code></pre> <p>the output is:</p> <pre><code>&lt;input type='submit' value='Save' /&gt; &lt;input type='submit' value='Save'&gt; &lt;input type="blah" /&gt; &lt;input&gt; </code></pre> <p>More generally though, if you're looking to test for compliance with xhtml, would <a href="http://lxml.de/parsing.html" rel="nofollow">lxml</a> make your life easier?</p>