Ubuntu – sed regex issue

regular expressionsedUbuntu

I'm trying to replace a string in a file:

$RELEASE     = '1234';

The whitespace between RELEASE and the = symbol could be either spaces OR tabs. The quotes around the version number could be either single or double.

I currently am assuming spaces and single quotes at the moment just to try to get it working:

sed 's/$RELEASE[[:space:]]*\=[[:space:]]*'\''[0-9]*'\'';/$RELEASE = '\''1234'\'';/g' config.ini > config.ini

So after a lot of work, this works. But only if the string is spaces (as apposed to tabs) and single quotes as apposed to doubles. Here is what I have so far for trying to tackle the tabs…:

sed 's/$RELEASE([[:space:]]|\t)*\=([[:space:]]|\t)*'\''[0-9]*'\'';/$RELEASE = '\''1234'\'';/g' config.ini > config.ini

I've just read that /t isn't supported in most sed regular expressions… Is this true? Is there a [[:tab:]] type replacement? (I did try that)

Any help would be appreciated.

Best Answer

I don't have any problem with [[:space:]]. Here's a really silly little example showing the mixed-replacement of spaces and tabs:

$ echo -e 'A \t \t B' | sed 's/A[[:space:]]*B/WORKED/'
WORKED

You can also use \s which is often preferable with big sed strings because it's much shorter:

$ echo -e 'A \t \t B' | sed 's/A\s*B/WORKED/'
WORKED

Anyway, I think your actual problem is escaping those troublesome single quotes. I find the easiest way is to break out of the single quote string and have a double-quoted single quote and then (if needed) go back into the single quote line. Bash will automatically concatenate this all up for you.

$ echo 'This is a nice string and this is a single quote:'"'"' Nice?'
This is a nice string and this is a single quote:' Nice?

So all the space we saved with \s is about to get destroyed by this mega-quote situation:

$ echo -e '$RELEASE  \t = '"'"'1234'"'"';' |\
  sed 's/$RELEASE\s*=\s*'"'"'[0-9]*'"'"'\;/REPLACEMENT/'

Of course there is an argument that (because this looks like a PHP script) that you might be able to assume that if the line starts with $RELEASE[\s=]+ you can just replace the whole line. Not always true obviously (the entire app could be one hideous line) but it makes your search and replace more palatable:

sed 's/$RELEASE[\s=]*.*/REPLACEMENT/'

And yes, general sed usage rules apply. Don't echo into a stream-editor (like sed) and redirect back into that file. If it works you could easily knacker the file.

Either use the -i argument (works for sed) or pipe into a application like sponge (which is like a delayed output):

sed -i '...' file
sed '...' file | sponge file
Related Question