regexsed

Why isn't sed matching a space with the \s character class?


I'm writing a script to update some config files. One of the config file lines looks like this:

hosts: [localhost]

I'm using to do the substitutions which is working fine, but that line I can not figure out. When I use:

sed -E "s/(^hosts:\s*)/\1testing/" config.yaml

it returns:

hosts:testing [localhost]

It seems ok but \s* did not not match the space. So I try:

sed -E "s/(^hosts:\s+)/\1testing/" config.yaml

and it doesn't match at all. When I replace the \s+ with an actual space it works and the full pattern:

sed -E "s/(^hosts: )\[[A-Za-z.]*\]/\1testing/" config.yaml

hosts: testing

Solution

  • Standard sed with -E uses Extended Regular Expressions syntax with a few differences.

    EREs do not treat \s as a character class.

    GNU sed, however, when not run with --posix does recognise it as such.

    The standard way to specify the space character class in an ERE is:

    [[:space:]]
    

    (That is [:space:] inside brackets - other characters / ranges / character classes can appear inside the outer brackets.)

    See: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap09.html#tag_09_03_05