impedindo que o prompt do terminal seja sobrescrito pela saída do programa

3

Suponha que eu execute um comando como este no terminal:

~$ echo 'sleep 2; echo "hello!"' | sh

depois, comece a digitar a próxima linha. Após dois segundos, as palavras "hello! \ N" serão inseridas em qualquer coisa que eu esteja escrevendo. Eu sei que há uma solução para isso (pressionando para cima e para baixo, que atualiza o prompt), no entanto, em outros sistemas que não têm histórico - por exemplo, usando um MUD através de telnet - isso não é possível.

Alguém sabe de um aplicativo ncurses ou emulador de terminal que separa stdin de stdout? Isso parece muito fácil de fazer em ncurses, você só tem que usar alguns dup2s inteligentes, mas antes de eu fazer isso eu quero saber se alguém já fez isso antes.

Quaisquer outras soluções para o problema principal são bem-vindas também.

    
por Blackle Mori 10.06.2015 / 07:32

2 respostas

5

Isso não é tão fácil quanto parece mudar. Está relacionado ao terminal cozido vs. modo cru e se o eco está ativado ou não.

Quando o terminal está no modo cozido (o padrão), o kernel lê tudo o que entra e o processa usando recursos de edição de linha rudimentares que incluem o eco do texto normal imediatamente, processando o apagamento e eliminando caracteres que apagam um único caractere e toda a linha atual, respectivamente, e algumas outras coisas. Linhas de texto só aparecem na entrada do terminal quando você pressiona enter. Durante todo o tempo até que você pressione enter, tudo acontece inteiramente dentro do kernel e nenhum processo em execução no terminal recebe um único byte , portanto, o aplicativo de primeiro plano nem sabe que o usuário está no processo de digitação de qualquer coisa. Um processo em execução no tty não pode suprimir esse eco, mesmo que ele queira apenas porque o eco viria em um momento inoportuno (por exemplo, misturado com a saída), porque esse processo nem mesmo está ciente de que a entrada está acontecendo.

Você pode configurar o terminal para o modo raw sem echo para suprimir isso ( stty raw , ou com termios), mas você perde completamente as capacidades de edição de linha do kernel - o que significa, por exemplo, que você não pode corrigir um erro de digitação. pressionando Ctrl - u e iniciando novamente. Mais importante, você terá muita dificuldade em usar qualquer programa que dependa do processamento cozido do kernel (basicamente qualquer coisa que não use readline ou ncurses) porque você estará digitando completamente cego em tais programas! Ah, e também: sem o processamento finalizado do terminal você perde a interceptação do kernel dos atalhos de controle de trabalho para interromper e suspender (por padrão Ctrl - c e Ctrl - z respectivamente).

    
por 10.06.2015 / 08:09
1

Você pode incluir alguns escapes ANSI no echo em segundo plano para enviar sua saída para o topo da tela:

printf %b\n 'sleep 2; printf "373[H3[Khello!38"' |sh

Provavelmente deveria fazê-lo. Ele requer um terminal compatível com ANSI basicamente capaz de funcionar, mas se você não tiver um desses, provavelmente deveria. Todo mundo tem usado desde os anos 80.

Em todos os casos, o% principal3 é o escape octal para o caractere literal < ESC > - como você pode pressionar no canto superior esquerdo do teclado. Todas as outras sequências são interpretadas pelo terminal na entrada como comandos de endereçamento do cursor.

Eles fazem essas coisas:

  • %código%
    • Salve o estado do cursor para restauração posterior.
  • %código%
    • Início do cursor - mova-o para a primeira coluna na primeira linha da tela.
  • %código%
    • Apague o texto na linha atual.
  • %código%
    • Restaurar o último estado do cursor salvo.

O resultado é que o processo em segundo plano endereça o cursor para o canto superior esquerdo da tela, limpa a linha, grava hello! e coloca o cursor de volta onde o encontrou. Combinações muito mais complicadas são possíveis - e poderiam ser usadas para desenvolver soluções mais robustas, mas foi o que consegui.

    
por 10.06.2015 / 23:00