[Discuss] sed and ANSI sequences

Derek Martin invalid at pizzashack.org
Sun Oct 16 20:01:07 EDT 2011


David, 

On Thu, Oct 13, 2011 at 03:00:04PM -0400, David Kramer wrote:
> I have a script at work that colorizes command outputs.  I've mentioned it here before.  I have
> the colors defined in environment variables:
> COLOR_ERROR='\e[37;41m'
> COLOR_GOOD='\e[32;40m'
> COLOR_RESET='\e[0m'
> COLOR_WARN='\e[33;40m'

These variables are literal strings, i.e. '\e' here is the
two-character string, '\' and 'e'.  The shell's built-in echo command
(with the -e option ONLY) interprets '\e' as an escape character.  But
you're not using it in that context; and sed does not interpret it
that way.  Also, the shell is going to interpret '\e' as 'e', which is
what sed will see.  You'll need to do two things for this to work:
First use '\\e', which will give you an escaped '\' as well as the e.
Then you need to pass this string to echo -e, so that it will get
interpreted as an escape char.

> > echo "This is a [WARNING] message " | sed -e 's/.*[WARNING].*/'${COLOR_WARN}'&'${COLOR_RESET}'/g;'

This should work, once you properly escape the 'e':

msg=`echo "This is a [WARNING] message " | sed 's//.*[WARNING].*/'${COLOR_WARN}'&'${COLOR_RESET}'/g;'`
echo -e $msg


I tried it locally with this:

$ off='\\e[0m'
$ bold='\\e[1m'
$ msg=`echo "bold is as bold does" | sed s/bold/${bold}bold${off}/g`
$ echo -e "$msg"
bold is as bold does

And both of the strings "bold" were printed in bold.

> I even tried adding an extra escape backslash
> > echo "This is a [WARNING] message " | sed -e
> 's/.*[WARNING].*/\'${COLOR_WARN}'&\'${COLOR_RESET}'/g;'

Again, the trick here is that only echo with the -e option treats '\e'
as an escape char.  So you need to feed the result of the sed command
to echo somehow.  It does not read from stdin, so the only way I can
think of to do that is to set a variable to the string you want to
print, and then echo -e $variable.

> PS: I did see one working example at
> http://travelingfrontiers.wordpress.com/2010/08/22/how-to-add-colors-to-linux-command-line-output/
> sed ''/crit/s//$(printf "\033[31mCRITICAL\033[0m")/g''

This works similarly... in this case, printf interprets \033 as an
escape sequence.  In both cases though, it's not the shell's
command-line parser  doing the interpreting; it's a behavior specific
to a built-in.

> However, it relies on the printf command, which means (1)launching
> another process and 2) not using sed's buffers, so I can't have a
> series of sed operations in one command.

Since you're relying on some program to interpret the '\e' sequence as
a literal escape program, you're stuck launching a separate process,
whether you go the echo route or the printf route (both are
shell-builtins in bash).  If you really want to avoid this, however,
there is a way:  Instead of writing '\e' in your code, press CTRL-V
ESC directly in your code, and that should insert a literal escape
character right in your code.  The down side of doing this is that it
can't be copy-pasted; you'll get a literal '^[' string instead of an
actual escape character.

But if you find that acceptable, then the following should work:


b='^[[1m' # Note that the '^[' is actually CTRL-V ESC
o='^[[0m'
echo "This is a [WARNING] message " | sed -e 's/.*[WARNING].*/'${b}'&'${o}'/g;'

 
> Also, I don't understand the doubled single quotes.  That should be
> the equivalent of no quotes at all.

I belive so.

-- 
Derek D. Martin    http://www.pizzashack.org/   GPG Key ID: 0xDFBEAD02
-=-=-=-=-
This message is posted from an invalid address.  Replying to it will result in
undeliverable mail due to spam prevention.  Sorry for the inconvenience.



More information about the Discuss mailing list