Different format in terminal vs in a .txt document

You have escape control sequences in your printf command i.e. printf "\33[2K....., (\e[2K clears a line), that is necessarily a control command for the terminal, that can only be understood and acted upon by a terminal device.

When you are running the script interactively inside the terminal, the terminal is interpreting the sequence properly. While saving the command's output in a file, the sequence is being treated literally as there is nothing to interpret the sequence then.

Now if you do:

cat test.txt

you'll see that the terminal is interpreting the sequence correctly again before the output being printed.


The succession of lines

printf "\33[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs
printf "\33[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs >> test.txt

is defined to print time information on the same line of a terminal. That \33[2K clears the entire (current) line, and the \r moves the cursor to the beginning of the line. The effect is to make the time information which changes, just appear to change that part of the line.

I noticed that there is no newline (\n) in the format. The question shows line-breaks (perhaps those were added for clarity).


You wrote it yourself, as

\33[2K

Depending on your terminal, it will understand that as an instruction to perform some action. Since you mentioned "console", you can consult the console_codes(4) man page, where this is listed:

ECMA-48 CSI sequences

CSI (or ESC [) is followed by a sequence of parameters, at most NPAR (16), that are decimal numbers separated by semicolons. An empty or absent parameter is taken to be 0. The sequence of parameters may be preceded by a single question mark.

...

K: EL - Erase line

default: from cursor to end of line.
ESC [ 1 K: erase from start of line to cursor.
ESC [ 2 K: erase whole line.

(It helps to recall that \033 is the same as ESC).

So your escape sequence is the "erase whole line" command to this terminal.

The portable (and clearer) way to write this would be

clear_line=`tput cr; tput el`
printf "${clear_line}%3d Days, %02d:%02d:%02d" $days $hours $mins $secs

Using tput means that when writing to a terminal that doesn't support the el action, or that supports it with a different escape sequence, you'll get the appropriate output rather than unintelligible garbage.


P.S. All that arithmetic is probably unnecessary, assuming GNU date. If you never exceed 7 days, you can get it down to

date -u -d "-$begin seconds +3days" '+${clear_line}%w days, %T'

Otherwise, you still need to compute $days, but you can format the seconds with %T:

now=$(date +%s)
diff=$(($now - $begin))
days=$(($diff / 86400))
date -u -d "00:00 $diff seconds" '+${clear_line}$days days, %T'