grep caret appears to have no effect

To find a space, you have to use [:space:] inside another pair of brackets, which will look like [[:space:]]. You probably meant to express grep -E '^[[:space:]]*h'

To explain why your current one fails:

As it stands, [:space:]*h includes a character class looking for any of the characters: :, s, p, a, c, and e which occur any number of times (including 0), followed by h. This matches your string just fine, but if you run grep -o, you'll find that you've only matched the h, not the space.

If you add a carat to the beginning, either one of those letters or h must be at the beginning of the string to match, but none are, so it does not match.


Looks like it assumes that [:space:] will only appear within a bracket expression (highlighted matches with *):

echo 'hello' | grep -E '^[:space:]*h'
*h*ello
echo 'hello' | grep -E '[^[:space:]]*h'
*h*ello
echo ' hello' | grep -E '^[[:space:]]*h'
* h*ello

This is explained by the following snippet from man grep (my highlighting):

Finally, certain named classes of characters are predefined within bracket expressions [...] Note that the brackets in these class names are part of the symbolic names, and must be included in addition to the brackets delimiting the bracket expression.