regexsed

How to replace a question mark in sed


I want to replace a? with b? where ? is a character, not a wildcard. Here is what I tried:

 echo "a?c" | sed 's/a\?/b?/'

I expect b?c, but it returns b??c. I also tried two backslashes between a and ?, it doesn't work either.


Solution

  • When not inside a bracket expression, the interpretation of an ordinary character preceded by an unescaped <backslash> is undefined, except for:

    [...]

    • The '?', '+', and '|' characters; it is implementation-defined whether "\?", "\+", and "\|" each match the literal character '?', '+', or '|', respectively, or behave as described for the ERE special characters '?', '+', and '|', respectively (see 9.4.3 ERE Special Characters).

    Note: A future version of this standard may require "\?", "\+", and "\|" to behave as described for the ERE special characters '?', '+', and '|', respectively.

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

    When BRE is being used, to avoid ? being treated as an ERE special character in implementations where \ turns it into one, don't use the backslash.

    For portability, if you want to use ERE, invoke sed with the -E flag which allows use of ? to mean zero-or-one and where escaping it with backslash has the effect you were expecting. (The BRE equivalent of ERE ? is \{0,1\}.)

    To avoid ? being treated as a metacharacter in either flavour, regardless of implementation, use a bracket expression: [?]