3

I have quite a big script written. The script works well, the issue I have is with redirect. I have done the following block for redirect to a log file:

log_location=/home/admin
exec > >(tee -i $log_location/health-check.log)
exec 2>&1
echo -e "Output will be saved at $log_location/health-check.log\n"

The script has the following for colors:

G="\033[32m"
N="\033[0m"
R="\033[31m"
Y="\033[33m"

The console output of this prints in the colored format for required characters. However, when I less the .log file, it ends up as a binary file and upon viewing I see something like this:

ESC[33mGSANESC[0m Service Status is              |ESC[32mUPESC[0m
ESC[33mMCSESC[0m Service Status is               |ESC[32mUPESC[0m
ESC[33mTomcatESC[0m Service Status is    |ESC[32mUPESC[0m
ESC[33mSchedulerESC[0m Service Status is         |ESC[31mDOWNESC[0m
ESC[33mMaintenanceESC[0m Service Status is       |ESC[31mSUSPENDEDESC[0m

I don't mind having non colored output in log files. Is there a way I can get this done?

1
  • 5
    Alternatively, you can use less -R for less to understand those escape sequences and pass them along to your terminal so the display is in colour. May 15, 2017 at 12:45

2 Answers 2

2

We could arrange a sed to strip the color codes from the output that goes to the log file. Though that requires getting the output from tee to stdout and to a pipe, so this isn't exactly straightforward. There might be better ways than the subshell-redirect trickery there. This seems to work with Bash and GNU sed, stdout gets a red error, the logfile gets no color codes:

#!/bin/bash
exec > >( (tee -a /dev/fd/7 | sed -Ee $'s/\033''\[[0-9][0-9]?m//g ' > logfile) 7>&1 )
N=$'\033[0m'
R=$'\033[31m'
echo "${R}error${N}: foo"

Another option in shell that avoids the effects with reopening /dev/fd/N on Linux:

#!/bin/bash
exec > >(
        exec 7>logfile
        while IFS= read -r x ; do 
                echo "$x"
                x=${x//$'\033'\[[0-9]m}
                x=${x//$'\033'\[[0-9][0-9]m}
                echo "$x" >&7
        done    
)
N=$'\033[0m'
R=$'\033[31m'
echo "${R}error${N}: foo"

Though this of course has problems with NUL bytes, but a log output probably does not have many of those. Possibly a Perl script would be best here.

If you only cared about messages printed from the script, you could make a function to print the message both to stdout and the logfile, and strip the color codes from the latter. That wouldn't help get the output from commands to the same log file, though.

3
  • Why tee -i? Upon ^C, sed will also get the SIGINT, so tee will get a SIGPIPE if it ignores the SIGINT. May 15, 2017 at 12:50
  • 1
    On Linux, you'd probably want tee -a. Otherwise if stdout goes to a regular file, tee would truncate it (open it at the start). tee -a is technically still not correct as it would write at the end instead of where the position currently is, but in practice the position is more likely to be at the end than at the beginning. May 15, 2017 at 12:52
  • @StéphaneChazelas, -i was in the original question, I don't know if they had a reason to use it (i.e. I didn't want to think if there is a corner case where it would be useful), but of course sed would die too. Given the use case, I don't think they're going to redirect stdout to a file, that's what the distinct log output is for.
    – ilkkachu
    May 15, 2017 at 19:14
0

You could use a sed/awk/... filter to strip the color definitions from the log in a tee based pipe redirection (as suggested by previous answer),

...or simply generate a colorless log output and let the log visualization tool itself handle the colorization: For example, multitail is a good tool candidate for that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.