O Shell não mostra comandos digitados, o "reset" funciona, mas o que aconteceu?

57

Meu problema é que o shell Bash para de mostrar os caracteres digitados nele. Ele lê os comandos embora.

Já me deparei com esse problema algumas vezes e não entendo o que o causa. Eu sei como resolver isso, mas eu realmente não gosto quando estou "vodu" minha maneira de sair dos problemas.

Descreverei as duas maneiras pelas quais me deparei com esse problema:

Estou executando um determinado processo, http://pythonpaste.org/script/ e, às vezes, quando eu paro isso ou quebra o controle, é devolvido ao shell. Quando eu digito comandos no shell, os caracteres digitados não aparecem. Quando pressiono enter, os comandos são enviados. Então, por exemplo:

  • Eu digito "ls"
  • Só vejo um prompt vazio e nada mais
  • Pressiono enter e recebo uma lista dos arquivos, em outras palavras: o comando é executado
  • quando eu dou o comando "reset" o shell começa a funcionar normalmente novamente

A segunda maneira que isso acontece é quando eu dou um comando como este:

$ grep foo * -l | xargs vim

Uso o grep para encontrar arquivos que tenham um determinado padrão e, em seguida, desejo abrir todos os arquivos resultantes do grep. Isso funciona como um encanto (embora não tão rápido quanto eu esperava). Mas quando saio do Vim, meu shell para de mostrar os caracteres digitados nele. Um comando de redefinição resolve o problema.

Meu palpite é que ambos os problemas têm uma razão subjacente, mas estou meio que perplexo em como ou qual é essa razão.

A pesquisa desse problema é problemática, porque a descrição é meio vaga e não possui termos de pesquisa rígidos.

Editar

Dando o

stty --all

comando conforme a solicitação de John S. Gruber deu a seguinte saída (espaço em branco editado para facilitar a leitura)

speed 0 baud;
rows 53;
columns 186;
line = 0;
intr = <undef>;
quit = <undef>;
erase = <undef>;
kill = <undef>; 
eof = <undef>;
eol = <undef>; 
eol2 = <undef>; 
swtch = <undef>; 
start = <undef>; 
stop = <undef>; 
susp = <undef>;
rprnt = <undef>; 
werase = <undef>; 
lnext = <undef>; 
flush = <undef>; 
min = 0; 
time = 0;
-parenb 
-parodd cs8 
-hupcl 
-cstopb cread 
-clocal 
-crtscts
-ignbrk 
-brkint 
-ignpar 
-parmrk 
-inpck 
-istrip 
-inlcr 
-igncr 
-icrnl 
-ixon 
-ixoff 
-iuclc 
-ixany 
-imaxbel 
-iutf8
-opost 
-olcuc 
-ocrnl 
-onlcr 
-onocr 
-onlret 
-ofill 
-ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig 
-icanon 
-iexten 
-echo 
-echoe 
-echok 
-echonl 
-noflsh 
-xcase 
-tostop 
-echoprt 
-echoctl 
-echoke
Niels Bom
fonte
2
Quando isso acontecer, insira stty --alle coloque os resultados em sua pergunta. Eco é uma característica tty que está sendo desativada. O Vim fará isso enquanto estiver em execução e também colocará o terminal no modo bruto. Ao sair, deve redefinir as configurações do terminal. Quando o vim está sendo executado, você não deseja repetir o icomando que coloca o editor no modo de inserção, por exemplo. Essas configurações informam ao dispositivo tty como ele deve processar o que você digita. Enquanto vim está em execução que cuida de ecoando o que deve ser feito eco, etc.
John S Gruber
Tenho os mesmos sintomas quando paro o Zope (com CTRL + C) quando ele está sendo executado em primeiro plano e estou em uma sessão de depuração de ipdb.
Mark van Lent
@MarkvanLent eu acho que eu tenho esse problema também
Niels Bom
@JohnSGruber Adicionei a saída de stty --allà minha pergunta. Desde já, obrigado!
Niels Bom

Respostas:

68

Ao executar um shell ou a maioria dos programas em um shell, qualquer coisa que você digitar é repetida no terminal do usuário pelo subsistema tty do kernel. Também há outro tratamento especial para apagar caracteres, Ctrl + R, Ctrl + Z e assim por diante.

Certos programas (em particular os editores) que são executados a partir de uma linha de comando não precisam ou querem isso. Por esse motivo, eles sinalizam o kernel com uma chamada IOCTL no dispositivo tty (terminal) de que não desejam esse comportamento. Eles também não querem que caracteres especiais façam coisas especiais. Em vez disso, eles solicitam ao kernel um modo "bruto". Em particular, o editor como o vim desativa várias "configurações de eco". Tudo isso se aplica aos terminais reais nas linhas seriais de um computador, ou aos terminais virtuais em Alt + Ctrl + F1, ou aos terminais realmente virtuais que você obtém ao executar algo como o gnome-terminal sob uma GUI.

Esses programas devem redefinir qualquer modo que eles alterem no tty virtual que estão usando antes de sair, digitando um comando quit editor ou recebendo um sinal (de Control + C), por exemplo.

Se eles não conseguirem fazer isso corretamente, o tty será deixado no estado engraçado que você descobriu. Como os programas podem falhar ao redefinir o terminal, o resetcomando foi gravado para permitir que o usuário se recupere.

Presumo que a interrupção esteja mexendo com o software python que você está executando. Eu acho que esse programa não está tendo a chance de redefinir o terminal ou simplesmente não está fazendo isso.

No caso do vim, quando executo seu exemplo, recebo o mesmo comportamento que você descreve. Também vejo a mensagem "Vim: Aviso: a entrada não é de um terminal" (desaparece quando você redefine). Isso ocorre porque o vim não é iniciado normalmente a partir do shell. Em vez disso, os comandos 'grep' e 'xargs' têm usado a entrada padrão, normalmente ocupada pelo tty, com a finalidade de passar os nomes de arquivo de greptto xargs.

Em sua saída publicada stty -a, podemos ver "-echo", também confirmando que este é o problema. Se você matasse o vim de forma que ele não pudesse lidar com o sinal normalmente, provavelmente veria o mesmo problema.

O problema é descrito em outro lugar em https://stackoverflow.com/questions/3852616/xargs-with-command-that-open-editor-leaves-shell-in-weird-state .

Uma solução para o caso vim é evitar xargs e usar:

 vim $(grep foo * -l)

Aqui, a lista de arquivos é construída pelo shell, como havia sido o xargs, mas o shell está chamando vim, que está diretamente conectado ao tty. Há uma mensagem de aviso enviada ao arquivo de saída de erro e o vim define e redefine as configurações tty corretamente.

Mais referências aqui , e outra interessante aqui . Outra solução interessante é fornecida em uma resposta para https://stackoverflow.com/questions/8228831/why-does-locate-filename-xargs-vim-cause-strange-terminal-behaviour .

John S Gruber
fonte
Obrigado pela explicação completa. A razão completa pela qual isso não funciona parece um rabino profundo (tty, ioctl, etc), então não posso dizer que entendo completamente, mas não é mais um vodu, então obrigado novamente!
Niels Bom
Para ser completo, posso executar grep foo * -l | vim -sem problemas. Então, acho que o problema não está no grep e no xargs, mas apenas no xargs. Você concordaria?
Niels Bom
11
Não é um problema com grep ou xargs. É um problema com o fato de o stdin não estar mais definido para o tty. Isso também falha `true | vi / tmp / afile1. Uma das referências menciona que o vim define stdin para stdout (ainda o tty) porque stdin foi definido como / dev / null nessas situações. Quando isso acontece, o vim pode se lembrar e redefinir o eco e outras configurações, mas não. Eu acho que isso é um problema com o vim.
John S Gruber
Isso foi muito útil, pois me deparei com isso. Parecia aleatório, mas aposto que era sempre quando eu tentava fazer algo com o vi que não saía de forma limpa ou usava um cachimbo.
Michael Mathews
11
Obrigado! Finalmente descobri como recuperar no OS X bash depois de um ctrl-c para git add -p!
26616 Steve Jansen
0

Iniciava um novo usuário no sistema (refiro-me a um novo usuário limpo e fazia o login lá) e veria se o problema estava lá. Caso contrário, é o seu terminal ou o seu X11.

Adobe
fonte
Eu adicionei um novo usuário e testei isso com o grep foo * -l | xargs vimcomando O problema ainda existe. Não entendo exatamente como minhas configurações do X11 podem influenciar a reação do meu terminal. Você poderia elaborar sobre isso? Obrigado!
Niels Bom