bind -x 使终端处于类似于 ^V 的状态

bind -x 使终端处于类似于 ^V 的状态

我像这样定义了一个 shell 键绑定~/.bashrc

bind -x '"\e\C-w":"/usr/bin/reset"'

这确实使可执行文件Ctrl-Alt-w启动reset。但是,它会使终端处于类似于按 进入的状态Ctrl-v。因此,例如,如果在以这种方式重置后立即按Ctrl-p,而不是调用该快捷方式的操作(重复上一个命令),我会得到^P打印。

知道是什么导致了这个问题以及如何解决它吗?

编辑:我附加了一个 Python 程序,它重现了我试图用reset.我在调试多线程应用程序时经常遇到这种情况:

import pdb, thread, time

def interrupt():
    time.sleep(2)
    pdb.set_trace()

thread.start_new_thread(interrupt, ())
raw_input('? ')

pdb.set_trace()要重现混乱的状态,只需运行上面的代码,然后在看到调用调试器时按 Enter(在运行程序并出现初始提示后大约两秒,它将打印一堆文本,以 结尾)。

答案1

运行reset会清除终端显示并将所有输入设置重置为默认值。特别是,它将输入模式设置为煮熟的,即终端一次读取一行,然后将整行发送到应用程序(这里,应用程序是 bash)。终端的行编辑器是一种极其原始的编辑器,只能理解退格键,没有什么新奇的。 Bash 提供了一个复杂的行编辑器;它将终端切换到原始模式,每个字符在键入后立即发送到应用程序。

如果您发现自己的终端混乱(没有行版本或 bash 提示符下没有回显),最简单的恢复方法是运行命令resetstty sane.通常您可以盲打它们并按Return。如果这不起作用(例如,因为终端处于熟模式并且行提交字符不是默认字符),您可以运行reset 2>/dev/pts/42(终端重新初始化)或stty sane </dev/pts/42(输入配置重新初始化)(注意不同的重定向),/dev/pts/42其中运行 shell 的终端。如果无法在其中运行命令,则查找终端名称可能需要一些猜测。在终端内,该命令tty将显示它。如果您可以在输出中找到正确的 bash 进程ps,则您需要该TTY列,/dev前面带有。

通过在 bash 提示符下键入这些命令来运行这些命令是正确的,但将它们作为 readline 宏的一部分运行则不然。 Bash 每次打印新提示时都会重置终端设置,因此您在编辑一行期间所做的操作不会持续到后续命令为止。

此外,如果您在行reset编辑期间运行,这会弄乱 bash 所依赖的参数:特别是,它将终端模式设置为“cooked”,而 bash 行编辑要求行编辑器逐字符接收输入。比较sttybash 命令行版本期间和不在 bash 提示符下的输出,我认为这些是您需要的设置:

bind -x '"\e\C-w": "reset; stty -icrnl -icanon -echo </dev/tty"'

如果您reset只是为了清除显示而调用,请调用而不是。tput rs1 rs2 rs3 rfreset

正如我上面所写,重置终端设置的正确方法是reset在 bash 提示符下运行。将其作为键绑定的一部分运行是行不通的,因为 bash 在显示下一个提示时会恢复上一个应用程序(导致终端设置混乱的应用程序)留下的设置。我不认为 bash 有任何内置功能可以将终端设置重置为正常的默认值,但如果需要,您可以通过用户配置来做到这一点,并在您的 中使用以下行.bashrc

PROMPT_COMMAND="$PROMPT_COMMAND
stty sane"

如果您确实希望有一个在行编辑期间重置终端设置的键绑定,那么您需要更复杂的东西。使 bashreset在提示符下运行命令(而不是作为编辑命令的一部分),然后恢复当前编辑。这在 bash 中并不容易做到,因为绑定只能是 readline 宏或 bash 函数,但不能混合使用两者。以下代码将Ctrl+ Meta+绑定W到 readline 宏,该宏通过绑定调用 bash 函数,然后accept-line通过其\C-m绑定调用 readline 函数,然后通过另一个绑定调用另一个 bash 函数。这bind -x绑定只能分配给长度为 1 或 2 的按键序列C-x LETTER,所以我对辅助宏使用很少使用的组合。

run_command_during_line_edition () {
  saved_READLINE_LINE=$READLINE_LINE saved_READLINE_POINT=$READLINE_POINT
  READLINE_POINT=0 READLINE_LINE=" $1"
  unset run_command_first
}
restore_saved_command () {
  READLINE_LINE=$saved_READLINE_LINE READLINE_POINT=$saved_READLINE_POINT
  unset saved_READLINE_LINE saved_READLINE_POINT
}
bind -x '"\C-xZ": "restore_saved_command"'
bind -x '"\C-xR": "reset; stty sane -icrnl -icanon -echo; run_command_during_line_edition reset"'
bind '"\e\C-w": "\C-xR\r\C-xZ"'

同样,您可能不需要所有这些复杂的操作 -reset在提示符处盲目键入,或者包含stty sane在您的 中PROMPT_COMMAND,应该可以解决您的问题。哦,或者您可以切换到 zsh,这一切都会变得轻而易举。

相关内容