Find and replace using regex in sed

12,680

Solution 1

You could use + to enforce at least one character which is not a #

Since the sed in OSX does not support the enhanced regular expression syntax like + by default, you need to pass the -E flag to sed. And the good news is -E flag works well on *nix systems too. When using the -E flag, you can skip escaping the special regex characters like +, (, etc.

sed -E "s/#([^#]+)#/===\1===/g" filename

Solution 2

The easiest way is to match the blanks too:

sed 's/# \([^#]*\) #/=== \1 ===/g' filename

Another way is to require multiple (one or more) non-hashes between the two hashes:

sed 's/#\([^#]\{1,\}\)#/===\1===/g' filename

The \{n,m\} is a quantifier notation that requires at least n occurrences and at most m occurrences of the pattern immediately before it, so it is generalization of the ?, * and + metacharacters (which can be represented by \{0,1\}, \{0,\}, and \{1,\} respectively). If m is missing, it means any number not smaller than n; if n is missing, it means any number not larger than m, and so is equivalent to 0. In my example, I'm using it as the classic, portable (to prehistoric versions of sed off Linux and Mac OS X) version of +.

Another way of writing that is:

sed 's/#\([^#][^#]*\)#/===\1===/g' filename

And you can combine the ideas, of course:

sed 's/# \([^#][^#]*\) #/=== \1 ===/g' filename
sed 's/# \([^#]\{1,\}\) #/=== \1 ===/g' filename
Share:
12,680
Sudar
Author by

Sudar

I am a developer from Chennai, India, mostly interested in WordPress, Android and Arduino programming. I write about my projects at my blog. You can also checkout my code that I have released as open source in my github account. You can follow me on twitter.

Updated on June 04, 2022

Comments

  • Sudar
    Sudar almost 2 years

    I want to replace

    # Bulk Delete #
    

    with

    === Bulk Delete ===
    

    I am using the following sed command.

    sed "s/#\([^#]*\)#/===\1===/g" filename
    

    It works, but it also replaces

    ### Translation
    

    with

    ======# Translation
    

    How to prevent it and make it work in both mac and ubuntu?

  • Tuxdude
    Tuxdude about 11 years
    @JonathanLeffler - updated the answer. Try with the -E -e flag, should work on both OSX and *nix
  • Jonathan Leffler
    Jonathan Leffler about 11 years
    The -e option universally (meaning all versions of sed) specifies that the next argument is part of the script; you can specify it multiple times to build up a complex script. On Mac OS X, you can use the -E option to invoke 'extended regular expressions', but then you don't need the backslashes: sed -E -e 's/#([^#]+#/===\1===/g'.
  • Tuxdude
    Tuxdude about 11 years
    Yes you're right about, -e which was optional. Should have mentioned that.
  • Jonathan Leffler
    Jonathan Leffler about 11 years
    OK—we're in agreement on Mac. I'm not sure about elsewhere. According to its help message, GNU sed (4.4.2) uses the -r option to invoke extended regular expressions. However, it seems to support -E as an undocumented synonym for -r.
  • Tuxdude
    Tuxdude about 11 years
    I tried it on my Linux box with GNU sed version 4.2.1 and it seems to be happy with -E. And yes you're right -r seems to be the option documented in the man page and I do not see -E. I'm not sure if the man page on my system is outdated.
  • Sudar
    Sudar about 11 years
    I knew about the -r option, but didn't know about -E. Thanks for mentioning it.
  • Sudar
    Sudar about 11 years
    Can you kindly explain 's/#\([^#]\{1,\}\)#/===\1===/g' a bit more, or point me to some documentation? I am slightly confused.
  • Sudar
    Sudar about 11 years
    Thank you for the explanation