2

Sometimes I accidentally cat some binary data; sometimes some ncurses program crash - for plenty of reasons terminal can end up in bad state, requiring manual reset. This is happening too often.

Such bad state can be no-echo, or converting everything to Chinese garbage, or many other things.

Is there any easy way to make sure terminal (without hard reset, clean-screen etc.) settings are restored when shell regains control?

It's bash and Terminal.app but I'd guess this problem is pretty much universal.

3 Answers 3

4

The problems that you mention arise in different layers and only some of them can be solved with “escape codes”.

Alternate Character Sets in the Terminal Emulation

There is a common terminal problem that might be described as “(some) lowercase letters are displayed as symbols or line drawing characters” (see this other SO question). This may not be related to your “Chinese garbage” problem, but it is the closest thing I have seen. You may also run into “Chinese garbage” when interpreting almost any 8-bit data stream as UTF-16 encoded text. Usually this is not a “sticky” problem that needs to be reset, so it is probably not the issue you are seeing.

The “stuck with line drawing characters” problem usually comes from sending the terminal emulator an unintentional control sequence (or stopping a program before it has reset the terminal after switching to the alternate character set). This can happen when some binary data is displayed and the byte stream contains a terminal control sequence that selects an alternate character set.

This is easy to trigger on most VT-100-style terminals since all it takes is a single byte (0x0e; see my answer to the previously linked SO question). The control sequence to reset this condition is also a single byte (0x0f; often produced via echo ^V^O (typed as echo Control+V Control+O, or directly typed as printf '\017').

You could clear up this type of problem** by getting your prompt to include a 0x0f byte.
** If your “Chinese garbage” is due to some other problem then it might have a different solution.

PS1="\[\017\]… "

The \[ and \] are there to tell bash that the bounded character is non-printing. This lets bash keep an accurate idea of “physical” cursor position (this is important for proper redisplay when using the command line editing functionality).


As Ignacio Vazquez-Abrams points out in his answer, another way to get the desired control sequence is via the tput command:

tput rmacs

Using this method you could avoid modifying PS1 and just put the above command in PROMPT_COMMAND:

PROMPT_COMMAND='tput rmacs'

TTY (termios) Options

The “no echo” problem*** comes from unexpected settings of the options for the OS-based tty device that connects your terminal emulator to all the programs that run inside terminal window. This is often cause by interactive text UI programs that have bugs, crash, or are killed so that they are not able to restore the tty to its original state.

You can control these settings with the stty command. This type of problem can not be solved with “escape codes” since the tty options are configured via software APIs (see tcsetattr(3) and termios(4)). Generally stty sane is a good reset mechanism.
*** Also “no ^C/^Z/^/”, “stair stepped output” (no automatic CR when an LF is received) and several other problems.

reset

The reset command can usually help with both types of problems. It will send terminal initialization control sequences that will usually fix the alternate character set problem, and it resets the tty options to reasonable values.

The problem with reset is that it also prints extra messages on some systems (e.g. “Erase is …”, “Interrupt is …”); you probably do not want these displayed before every prompt. If your implementation of reset sends the messages and the control sequences to different places (e.g. one goes to stdout while the other goes to stderr) then you might be able to filter out the messages (e.g. PROMPT_COMMAND='reset 2>/dev/null' (see below) and skip putting ^O into the prompt).

^O and stty sane

In bash, you can set the parameter PROMPT_COMMAND to command and bash will run if before displaying the primary prompt. You could put all call to stty sane in there and put ^O in your prompt:

PROMPT_COMMAND='stty sane'
PS1="\[\017\]… "

Again, you could avoid modifying PS1 (and handle non-VT-100-style terminals) by using tput (as suggested by Ignacio Vazquez-Abrams):

PROMPT_COMMAND='stty sane; tput rmacs'
3
  • This must be more than a single byte, as I cannot reproduce it by head /dev/urandom - it outputs garbage just as expected, but then I get normal prompt back. And of course terminal is set to UTF-8, which is self-synchronizing. It's probably some terminal escape sequences. Are there any simple ways to test common problems and if particular solution fixes them?
    – taw
    Oct 7, 2010 at 3:47
  • @taw: It sounds like your “Chinese garbage” problem is not caused by the alternate character set selection. Actually, the “line drawing instead of lowercase letters” is usually what people see when wedged in alternate character set mode. Unfortunately I do not know of an easy way to diagnose terminal emulation issues. You could try capturing some problematic output via script (if you can reliably reproduce the situation) and isolating the problematic sequence by replaying parts of the captured output in fresh terminals (use a binary search technique to avoid having to test each byte offset). Oct 7, 2010 at 6:18
  • @taw: You can trigger the alternate character set issue (“other symbols and line drawing instead of lowercase”) with head /dev/urandom, but you must first enable the alternate character set via tput enacs (or the equivalent, multibyte control sequence <ESC> ) 0; this is decidedly less likely than plain ^N in a random binary stream). Pretty much any terminal instance that has previously run a program that uses line drawing characters will have this already enabled; so, you could try head /dev/urandom after running some line-drawing program to see the effect and test ^O. Oct 7, 2010 at 6:28
1

Put

echo -n "$(tput rmacs)"

in $PROMPT_COMMAND.

1
  • 1
    tput rmacs is a better way of getting out of alternate character set mode (it is not specific to VT-100 style terminals), but it will not help with the termios problems. Also there is probably no need for echoing the result of a command substitution (just run it directly; the control sequence output by tput is highly unlikely to have its own newline). Oct 6, 2010 at 6:45
0

So i'll be less command line, you always have in xterm or in any terminal a "button" reset or hard reset, for terminal.app it is under Shell menu. Send Hard reset alt-command-r.

1
  • Well, the OP did say “without hard reset” in the question. Oct 7, 2010 at 6:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .