I notice that with the TERM
environment variable set to either xterm
or xterm-256color
that Mac OS X’s Terminal.app utility respects most ANSI escape codes, as least when those escape codes pertain to changing text color.
For example:
echo -e "\033[0;31mERROR:\033[0m It worked"
Produces:
However, I’m more interested in the cursor location manipulation functionality afforded by ANSI escape codes. Unfortunately, that type of code doesn’t seem to work too well in Terminal.app, from what I’ve been able to gather. For example, what I want to do is something like this:
echo -e "\033[sHello world\033[uG'day"
ESC[s
Saves the current cursor position, whereas ESC[u
restores the last saved position. As a result of running the script above, I’d expect the five characters in “G'day” to overwrite the five characters of “Hello” after the cursor has been repositioned, producing the following:
G'day world
Indeed, this is exactly what I get with iTerm2.app, ConEmu for Windows (running either MinGW or MSYS Git’s copy of bash.exe), etc. What I see in Terminal.app, however, is this:
Hello worldG'day
Is there a reason for this, aside form Terminal.app simply lacking support for these codes? Is there a way to enable this functionality? Is there a chance I have something misconfigured? My TERM setting? Something else?
I’ve been searching everywhere, but haven’t found anything relevant to Terminal.app, specifically. I find it odd that it would support colored text via ANSI escape codes, but not cursor repositioning through the exact same technology. That seems like a fairly arbitrary subset of a fairly well-defined standard. That’s what makes me think I’ve got something misconfigured, rather than that Terminal.app is the one to blame… but, I suppose it’s possible that it simply can’t be done. (Probably one of the reasons iTerm2 exists in the first place?)
If anyone could shed some light on this situation, it’d be much appreciated!
UPDATE
So, I've done a bit more reading and experimenting, and discovered the following oddity:
After looking into n.m.'s answer below, I decided to write out the bytes that were being returned by tput
to a file to see how they differed from the regular ANSI instruction.
$ echo "$(tput sc)Hello world$(tput rc)G'day" > out.bin
$ cat -e out.bin
^[7Hello world^[8G'day$
It appears that everything works as expected if I send it the sequences ESC
7
and ESC
8
, but NOT if I send it ESC
[s
and ESC
[u
, which as I understand things is the more typical representation of the ANSI SCP and RCP codes (Save Cursor Position and Restore Cursor Position, respectively). Since putting ASCII decimal characters 7
or 8
next to an escaped octal byte representation is impossible (\0337
!= ESC
), environment variables can be used instead to avoid relying on tput
:
$ esc=$'\033'
$ csi="${esc}["
$ echo "${csi}0;31mERROR:${csi}0m It worked."
ERROR: It worked. # Color works, as before
$ echo "${csi}sHello world${csi}uG'day"
Hello worldG'day # No dice
$ echo "${esc}7Hello world${esc}8G'day"
G'day world # Success
I'm not sure why this is. If ESC
7
and ESC
8
are some kind of proprietary or custom code for ANSI SCP and RCP that has the potential to vary from terminal implementation to terminal implementation, it would explain to me why tput
was created in the first place.
Unfortunately, I am unable to use tput
for what I am currently working on, as I am not working exclusively in a bash environment. I am more curious as to how the raw bytes are interpreted from terminal to terminal, and more specifically, whether or not there's a way to get Terminal.app to respect the same ANSI escape codes that all of the other terminal emulators I've tried seem to have no problem with. Is that possible? At this point, I'm beginning to think it simply might not be, which is fine, but it would be nice to know for sure, and possibly also to learn the reason why.