I define a shell keybinding in my ~/.bashrc
like so:
bind -x '"\e\C-w":"/usr/bin/reset"'
This does make Ctrl-Alt-w
launch the reset
executable. However, it leaves the terminal in a state that resembles the one you get into by pressing Ctrl-v
. So, for example, if immediately after resetting in this way I press Ctrl-p
, instead of invoking the action of that shortcut (repeat previous command) I get ^P
printed.
Any idea what's causing this problem and how to fix it?
EDIT: I am attaching a Python program that reproduces the messed-up terminal state I am trying to fix with the reset
. I encounter this condition very often while debugging multi-threaded applications:
import pdb, thread, time
def interrupt():
time.sleep(2)
pdb.set_trace()
thread.start_new_thread(interrupt, ())
raw_input('? ')
To reproduce the messed-up state, just run the code above, and press Enter when you see the debugger invoked (it will print a bunch of text, ending with pdb.set_trace()
, about two seconds after you run the program and the initial prompt appears).
Best Answer
Running
reset
clears the terminal display and also resets all input settings to their default. In particular, it sets the input mode to cooked, i.e. the terminal reads one line at a time before sending the whole line to the application (here, the application is bash). The terminal's line editor is an extremely primitive one that only understands backspace, nothing fancier. Bash provides a sophisticated line editor; it switches the terminal to raw mode, where each character is sent to the application as soon as it's typed.If you find yourself with a messed up terminal (no line edition or no echo at the bash prompt), the easiest way to restore it is to run the command
reset
orstty sane
. Usually you can type them blind and press Return. If that doesn't work (e.g. because the terminal is in cooked mode and the line submission character isn't the default one), you can runreset 2>/dev/pts/42
(terminal reinitialization) orstty sane </dev/pts/42
(input configuration reinitialization) (note the different redirections) where/dev/pts/42
is the terminal that the shell is running in. Finding the terminal name if you can't run commands in it may take a bit of guessing. From within the terminal, the commandtty
would display it. If you can find the right bash process in theps
output, you want theTTY
column, with/dev
in front.Running these commands by typing them at the bash prompt does the right thing, but running them as part of a readline macro not so much. Bash resets the terminal settings each time it prints a new prompt, so what you do during the edition of one line doesn't last until subsequent commands.
Furthermore, if you run
reset
during the edition of a line, this messes up the parameters that bash relies on: in particular, it sets the terminal mode to cooked, whereas bash line edition requires that the line editor receives the input character by character. Comparing the output ofstty
during a bash command line edition and while not at a bash prompt, I think these are the settings you need:If you're calling
reset
only to clear the display, calltput rs1 rs2 rs3 rf
instead ofreset
.As I wrote above, the right way to reset the terminal settings is to run
reset
at the bash prompt. Running it as part of a key binding doesn't work because bash restores the settings left over by the last application (the one that left the terminal settings in a mess) when it displays the next prompt. I don't think bash has any built-in feature to instead reset terminal settings to a sane default, but you can do that with user configuration if you want, with the following line in your.bashrc
:If you really want to have a key binding that resets the terminal settings during line edition, you need something more sophisticated. Cause bash to run the
reset
command at a prompt (as opposed to as part of an editing command) then resume the current edit. This isn't easy to do in bash because bindings can only be readline macros or bash functions but you can't mix the two. The following code binds Ctrl+Meta+W to a readline macro that calls a bash function via a binding, then calls theaccept-line
readline function via its\C-m
binding, and then calls another bash function via another binding. Thebind -x
bindings can only be assigned to key sequences of length 1 or 2, so I use little-usedC-x LETTER
combinations for the helper macros.Again, you probably don't need all that complication — blindly typing
reset
at the prompt, or includingstty sane
in yourPROMPT_COMMAND
, should solve your problem. Oh, or you could switch to zsh where all of this would be a breeze.