Bash

bind -x 使終端處於類似於 ^V 的狀態

  • March 9, 2019

~/.bashrc像這樣定義了一個shell鍵綁定:

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('? ')

要重現混亂的狀態,只需執行上面的程式碼,當你看到調試器被呼叫時按 Enter 鍵(它會在你執行程序大約兩秒鐘後列印一堆以 結尾的文本pdb.set_trace()並出現初始提示)。

執行reset會清除終端顯示並將所有輸入設置重置為其預設值。特別是,它將輸入模式設置為cooked,即終端一次讀取一行,然後將整行發送給應用程序(這裡,應用程序是bash)。終端的行編輯器是一個極其原始的,只懂退格,沒有什麼花哨的。Bash 提供了一個複雜的行編輯器;它將終端切換到原始模式,每個字元在輸入後立即發送到應用程序。

如果您發現自己的終端混亂(沒有行版本或在 bash 提示符下沒有回顯),恢復它的最簡單方法是執行命令resetstty sane. 通常您可以盲打並按Return。如果這不起作用(例如,因為終端處於熟模式並且行送出字元不是預設字元),您可以執行reset 2>/dev/pts/42(終端重新初始化)或stty sane </dev/pts/42(輸入配置重新初始化)(注意不同的重定向)在/dev/pts/42哪裡shell 正在執行的終端。如果您無法在其中執行命令,則查找終端名稱可能需要一些猜測。在終端內,該命令tty將顯示它。如果您可以在ps輸出中找到正確的 bash 程序,則需要該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](http://linux.die.net/man/1/tput) [rs1 rs2 rs3 rf](http://linux.die.net/man/5/terminfo)``reset

正如我上面所寫,重置終端設置的正確方法是reset在 bash 提示符下執行。將其作為鍵綁定的一部分執行不起作用,因為 bash 在顯示下一個提示時會恢復上一個應用程序(使終端設置混亂的應用程序)留下的設置。我不認為 bash 有任何內置功能可以將終端設置重置為正常的預設值,但是如果需要,您可以使用使用者配置來執行此操作,在您的以下行中.bashrc

PROMPT_COMMAND="$PROMPT_COMMAND
stty sane"

如果你真的想要一個在行編輯期間重置終端設置的鍵綁定,你需要更複雜的東西。使 bashreset在提示符處執行命令(而不是作為編輯命令的一部分),然後恢復目前編輯。這在 bash 中並不容易做到,因為綁定只能是 readline 宏或 bash 函式,但您不能將兩者混合使用。以下程式碼將Ctrl++Meta綁定W到一個 readline 宏,該宏通過綁定呼叫 bash 函式,然後accept-line通過其綁定呼叫 readline 函式\C-m,然後通過另一個綁定呼叫另一個 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,所有這一切都變得輕而易舉。

引用自:https://unix.stackexchange.com/questions/171367