bind -x deixa o terminal em um estado parecido com ^ V

2

Eu defino um atalho de teclado no meu ~/.bashrc da seguinte forma:

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

Isso faz com que Ctrl-Alt-w lance o executável reset . No entanto, ele deixa o terminal em um estado parecido com o que você está pressionando pressionando Ctrl-v . Então, por exemplo, se imediatamente após a redefinição dessa forma eu pressionar Ctrl-p , em vez de invocar a ação desse atalho (repetir o comando anterior), recebo ^P impresso.

Alguma ideia do que está causando esse problema e como corrigi-lo?

EDIT : Para ajudar os possíveis respondentes, estou anexando um programa em Python que reproduz o estado do terminal confuso que estou tentando corrigir com o reset . Eu encontro essa condição com muita freqüência durante a depuração de aplicativos multi-threaded:

import pdb, thread, time

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

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

Para reproduzir o estado bagunçado, basta executar o código acima e pressionar Enter quando vir o depurador invocado (ele imprimirá um monte de texto, terminando com pdb.set_trace() , cerca de dois segundos depois de executar o programa e o prompt inicial aparece).

    
por Dun Peal 04.12.2014 / 02:16

1 resposta

4

A execução de reset limpa a exibição do terminal e também redefine todas as configurações de entrada para o padrão. Em particular, ele define o modo de entrada para cozido , ou seja, o terminal lê uma linha por vez antes de enviar a linha inteira para o aplicativo (aqui, o aplicativo é bash). O editor de linhas do terminal é extremamente primitivo e entende apenas o backspace, nada mais sofisticado. O Bash fornece um sofisticado editor de linhas; ele alterna o terminal para o modo raw, onde cada caractere é enviado para o aplicativo assim que é digitado.

Se você se deparar com um terminal confuso (sem edição de linha ou sem eco no prompt do bash), a maneira mais fácil de restaurá-lo é executar o comando reset ou stty sane . Normalmente você pode digitá-los cego e pressionar Return . Se isso não funcionar (por exemplo, porque o terminal está no modo cozido e o caractere de envio de linha não é o padrão), você pode executar reset 2>/dev/pts/42 (reinicialização do terminal) ou stty sane </dev/pts/42 (reinicialização da configuração de entrada) redirecionamentos diferentes), onde /dev/pts/42 é o terminal em que o shell está sendo executado. Encontrar o nome do terminal, se você não puder executar comandos nele, pode levar um pouco de adivinhação. De dentro do terminal, o comando tty iria exibi-lo. Se você puder encontrar o processo bash correto na saída ps , você deseja a coluna TTY , com /dev na frente.

Executar esses comandos digitando-os no prompt do bash faz a coisa certa, mas executando-os como parte de uma macro de readline não muito. O Bash redefine as configurações do terminal cada vez que imprime um novo prompt, então o que você faz durante a edição de uma linha não dura até comandos subseqüentes.

Além disso, se você executar reset durante a edição de uma linha, isso atrapalha os parâmetros que o bash confia: em particular, ele configura o modo terminal para cozido, enquanto a edição bash requer que o editor de linha receba o comando. caractere de entrada por caractere. Comparando a saída de stty durante uma edição de linha de comando bash e enquanto não estiver em um prompt bash, acho que essas são as configurações que você precisa:

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

Se você estiver chamando reset apenas para limpar a exibição, chame tput rs1 rs2 rs3 rf em vez de reset .

Como escrevi acima, a maneira correta de redefinir as configurações do terminal é executar reset no prompt do bash. Executá-lo como parte de uma ligação de chave não funciona porque o bash restaura as configurações deixadas pelo último aplicativo (aquele que deixou as configurações do terminal em uma confusão) quando ele exibe o próximo prompt. Eu não acho que o bash tenha algum recurso embutido para redefinir as configurações do terminal para um padrão normal, mas você pode fazer isso com a configuração do usuário, se desejar, com a seguinte linha no seu .bashrc :

PROMPT_COMMAND="$PROMPT_COMMAND
stty sane"

Se você realmente deseja ter uma ligação de chave que redefina as configurações do terminal durante a edição de linha, você precisa de algo mais sofisticado. Porque bash para executar o comando reset em um prompt (em oposição a como parte de um comando de edição), em seguida, retomar a edição atual. Isso não é fácil de fazer no bash, porque as ligações podem ser apenas macros readline ou funções bash, mas você não pode mixar as duas. O código a seguir liga Ctrl + Meta + W a uma macro readline que chama uma função bash através de uma ligação e, em seguida, chama o accept-line readline função através de sua ligação \C-m e, em seguida, chama outra função bash via outra ligação. As ligações bind -x podem só pode ser atribuído a seqüências-chave de comprimento 1 ou 2 , então eu uso combinações C-x LETTER pouco usadas para as macros auxiliares.

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"'

Novamente, você provavelmente não precisa de toda essa complicação - digitar cegamente reset no prompt ou incluir stty sane no seu PROMPT_COMMAND deve resolver seu problema. Ah, ou você poderia mudar para zsh, onde tudo isso seria uma brisa.

    
por 04.12.2014 / 03:16