Bash tee remove color

I am currently using the following to capture everything that goes to the terminal and throw it into a log file

exec 4<&1 5<&2 1>&2>&>(tee -a $LOG_FILE) 

however, I do not want the color escape codes / interference to enter the log file. so i have something like this that sorta works

 exec 4<&1 5<&2 1>&2>&>( while read -u 0; do #to terminal echo "$REPLY" #to log file (color removed) echo "$REPLY" | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' >> $LOG_FILE done unset REPLY #tidy ) 

besides read waits for a carriage return, which is not ideal for some parts of the script (for example, echo -n "..." or printf without \n ).


Answer to Jonathan Leffler's question:

In the sample script test.sh :

 #!/bin/bash LOG_FILE="./test.log" echo -n >$LOG_FILE exec 4<&1 5<&2 1>&2>&>(tee -a >(sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' > $LOG_FILE)) ##### ##### ##### # Main echo "starting execution" printf "\n\n" echo "color test:" echo -e "\033[0;31mhello \033[0;32mworld\033[0m!" printf "\n\n" echo -e "\033[0;36mEnvironment:\033[0m\n foo: cat\n bar: dog\n your wife: hot\n fix: A/C" echo -n "Before we get started. Is the above information correct? " read YES echo -e "\n[READ] $YES" >> $LOG_FILE YES=$(echo "$YES" | sed 's/^\s*//;s/\s*$//') test ! "$(echo "$YES" | grep -iE '^y(es)?$')" && echo -e "\nExiting... :(" && exit printf "\n\n" #...some hundreds of lines of code later... echo "Done!" ##### ##### ##### # End exec 1<&4 4>&- 2<&5 5>&- echo "Log File: $LOG_FILE" 
  • The output to the terminal is as expected, and there are no color codes / interference in the log file in the log file. However, when examining test.log I do not see [READ] ... (see line 21 of test.sh ).

  • The log file [of my actual bash script] contains the line Log File: ... at the end of it even after closing 4 and 5 fs. I was able to solve the problem by putting sleep 1 in front of the second exec - I assume the race conditions or fd shenanigans are to blame. Unfortunately for you guys, I cannot reproduce this problem with test.sh , but I would be interested in any assumptions that everyone might have.

+8
bash logging exec tee
source share
6 answers

Consider using the pee program discussed in Is it possible to extend stdin to parallel processes . This will allow you to send log data through a sed script, while continuing to send colors to the actual output.

One of the main advantages of this is that it removes "run sed once in the log output line"; it's really diabolical for performance (in terms of the number of processes running, if nothing else).

+3
source share

I know this is not an ideal solution, but cat -v will make invisible characters, such as \x1B , converted to visible form, for example ^[[1;34m . The output will be dirty, but at least it will have the text ascii.

+1
source share

You can try using the -n option to read. It reads n characters instead of waiting for a new line. You can install it in one. This would increase the number of iterations of the code, but did not expect new lines.

From a person:

-n NCHARS read returns after reading NCHARS characters rather than waiting for a complete line of input.

Note. I have not tested this

0
source share

You can use ANSIFilter to split or convert console output using ANSI escape sequences.

See http://www.andre-simon.de/zip/download.html#ansifilter

0
source share

I use such things for this, setting TERM=dumb before running my command. This pretty much removed any control characters except tabs, CR and LF. I have no idea if this works for your situation, but it's worth a try. The problem is that you will not see the color coding on your terminal, as it is a mute terminal.

You can also try either vis or cat (especially the -v ) and see if they will do anything for you. You simply put them in your pipeline as follows:

 exec 4<&1 5<&2 1>&2>&>(tee -a | cat -v | $LOG_FILE) 

By the way, almost all terminal programs have the ability to capture input, and most of them will clear you. What platform are you working on and what type of terminal program are you using?

0
source share

Could screen -L or script commands be viable parameters instead of this exec loop?

0
source share

All Articles