Parando a saída de um programa executado na sessão SSH NOW

18

Problema

Eu executo um comando que gera muitas informações através do SSH. Por exemplo, tolamente adiciono informações de depuração dentro de um loop que é executado milhões de vezes, ou apenas executado cat /dev/urandompor chutes.

O terminal está inundado de informações.

Exemplo do que estou falando

Quero finalizar o comando o mais rápido possível e corrigir meu programa. Eu não ligo para o que imprime. Agora, pressione Ctrl+ CASAP (no exemplo acima, pressionei-o imediatamente após executar o comando), mas ainda leva tempo para imprimir todas as informações de que não preciso .

O que eu tentei

Tentei pressionar Ctrl+ com Ctanta força que teve resultados engraçados quando o terminal finalmente alcançou:

OUTPUT HERE^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
^C^C

^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C

Eu também li sobre Ctrl+, Sque aparentemente é usado para dizer ao terminal "parar a saída, preciso recuperar o atraso", mas aparentemente não faz nada.

Detalhes diversos

Gostaria de não alterar o comando que executo para que eu possa me resgatar em qualquer situação, mesmo que não me lembre de que o programa executado pode acabar assim.

Meu cliente SSH é executado no Cygwin ( CYGWIN_NT-6.1-WOW64 luna 1.7.30(0.272/5/3) 2014-05-23 10:36 i686 Cygwin) no MinTTY com o tipo de terminal definido como xterm-256color.

O servidor SSH é executado no Debian ( Linux burza 3.2.0-4-686-pae #1 SMP Debian 3.2.51-1 i686 i686 i686 GNU/Linux).

rr-
fonte
Em qual sistema você está executando os programas reais que produzem a saída? Linux, Unix ou Windows? O Linux e o UNIX devem aceitar Ctrl-O, o que significa "descartar qualquer saída gravada neste terminal".
Mark Plotnick
O servidor roda no Debian. Editou a pergunta. Ctrl-O parece não fazer nada também. Talvez seja a coisa do cliente?
RR
Você pode tentar iniciar seu xterm com a -jopção, para ativar a rolagem de salto. O problema básico é que o controle remoto pode enviar dados mais rapidamente do que a janela do terminal pode exibi-los - por padrão, ele deve bitblt o conteúdo da janela toda vez que uma nova linha é impressa. Muitos dados podem ser armazenados em buffer no momento em que seu Ctrl-C é recebido pelo sistema remoto, e seu programa de terminal tenta exibir todos eles.
Mark Plotnick
Apenas uma idéia: se você tem alguns comandos exatos que normalmente executa acidentalmente e eles geram muita saída, por que não acrescentar alguns aliases a .bashrc?
precisa saber é
Você poderia usar mosh em vez de ssh: mosh.mit.edu
gmatht

Respostas:

5

Parte dessa saída será armazenada em buffer. Você envia seu Ctrl+ Cpara a extremidade remota, que interrompe o programa em execução. O programa existe e o shell envia os caracteres para mostrar o prompt novamente. Antes que o prompt seja exibido, sua tela mostrará primeiro todos os dados que foram armazenados em buffer e que já estão a caminho.

O que você está pedindo é que o programa pare e os dados em trânsito desapareçam de alguma forma. Isso não pode acontecer, pois já está a caminho.

A única maneira de garantir que você não veja esses dados é sair do terminal e reconectar-se ao seu controle remoto - mas isso é provavelmente muito mais esforço do que aguardar a exibição dos dados em buffer.

garethTheRed
fonte
10

Normalmente, eu executo a saída lesspara que eu possa matá-la lessusando a qchave.

$ cmd | less

Exemplo

$ cat /dev/urandom | less

   ss # 2

Depois de pressionar q+, Enterele sairá e voltará ao seu terminal normal, deixando-o agradável e limpo.

Por que isso acontece?

O problema que você está enfrentando é que existem buffers (para STDOUT) que estão sendo colocados na fila com a saída do seu monitor. Esses buffers são preenchidos tão rapidamente que você não consegue interrompê-lo rápido o suficiente para pará-lo.

                                    ss # 1

Para desativar / limitar esse efeito, você pode desativar o buffer STDOUT, o que deve tornar as coisas um pouco mais responsivas stdbuf, mas você provavelmente precisará brincar com essas configurações para obter as coisas da maneira que desejar. Para remover o buffer do STDOUT, você pode usar este comando:

$ stdbuf -o0 <cmd>

A página de manual para stdbufdetalhes das opções à sua disposição:

    If MODE is 'L' the corresponding stream will be line buffered.  This 
    option is invalid with standard input.

    If MODE is '0' the corresponding stream will be unbuffered.

    Otherwise MODE is a number which may be followed by one of the 
    following: KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so
    on for G, T, P, E, Z, Y.  In this case the corresponding stream will be 
    fully buffered with the  buffer  size  set  to  MODE
    bytes.

Para um bom histórico de como o buffer funciona, eu sugiro dar uma olhada neste Pixel Beat articulado intitulado: buffering em fluxos padrão . Inclusive inclui belas fotos.

Referências

slm
fonte
Isso é razoável contanto que você lembre-se de acrescentar |lessque cmd, o que, infelizmente, muitas vezes não o fazem. Se você executar cmd, ainda precisará aguardar até que a impressão dos resultados seja concluída antes de receber ^C.
precisa
11
Isso realmente não explica o que está acontecendo. Afinal, não há canal envolvido, então a que buffer você está se referindo?
Gilles 'SO- stop be evil' '
@ Gilles - desculpe, o buffer seria o buffer para a tela.
slm
Qual buffer? No kernel? No xterm?
Gilles 'SO- stop be evil'
@Gilles - me dê um minuto, estou procurando os detalhes 8-)
slm
3

Existem vários níveis de buffer. Quando você pressiona Ctrl+ C, isso impede que o programa emita dados para o terminal. Isso não afeta os dados que o emulador de terminal ainda não exibiu.

Quando você exibe dados em velocidade muito alta, o terminal não consegue acompanhar e fica atrasado. É isso que está acontecendo aqui: exibir texto é muito mais caro do que produzir esses números aleatórios. Sim, mesmo com uma fonte de bitmap - produzir números aleatórios com qualidade criptográfica é muito barato em comparação. (Acabei de experimentar na minha máquina e o processo X saturou a CPU, com xtermalguns% e cat(contra os quais a geração de números aleatórios é considerada) mal atingindo 1%. E isso é com uma fonte de bitmap).

Se você quiser que isso pare agora, mate o emulador de terminal. Se você não quiser fazer isso, pelo menos minimize a janela; emuladores de terminal inteligentes (como o xterm) não mapeiam a janela, o que economiza o tempo da CPU X, portanto o lixo terminará a exibição mais rapidamente. O servidor X tem alta prioridade, portanto, isso fará uma grande diferença na capacidade de resposta da sua máquina enquanto o xterm está processando os dados em segundo plano.

Quando tudo isso acontece em um shell remoto, o atraso é ainda pior, porque os dados produzidos por catprecisam primeiro passar pela conexão SSH. Sua pressão de Ctrl+ Ctambém precisa passar pela conexão SSH; obtém prioridade um pouco maior (é enviada para fora da banda), mas isso ainda leva algum tempo durante o qual mais saída se acumula. Não há como suprimir dados em trânsito antes de fechar a conexão SSH (o que você pode fazer pressionando Enterentão ~.).

Gilles 'SO- parar de ser mau'
fonte
O problema está relacionado ao SSH junto. O buffer STDOUT não deve ser usado no modo interativo, mas o SSH não pode manipular o modo interativo corretamente. Embora muita saída possa travar na transação, é o processo SSH que recebe Ctrl + C, por isso é sua responsabilidade eliminar a saída quando é impossível passar Ctrl + C para controle remoto.
user4674453 4/4
@ user4674453 Uh? Ctrl + C não deve matar a saída local. Esse não é o seu trabalho. Ele deve ser passado para o lado remoto, o que pode ou não matar o processo remoto.
Gilles 'SO- stop be evil'
"É suposto ser passado para o lado remoto, o que pode ou não matar o processo remoto". - não é suposto fazer isso também. Os sinais KILL, Ctrl + C estão emitindo um deles, são apenas para processo local. Se não for usado para o processo local, a noção de "suposto" não será aplicável.
user4674453
@ user4674453 Não. Ctrl + C não é um sinal de interrupção. É um sinal de interrupção. Sua função é retornar a um prompt interativo. Ele mata apenas programas que não têm um prompt interativo para retornar.
Gilles 'SO- stop be evil'
"É um sinal de interrupção." É um argumento para matar o comando, portanto, é um sinal de morte. Às vezes, está sendo chamado como sinal POSIX, se quiser. "Seu papel é retornar a um prompt interativo. Ele mata apenas programas que não têm um prompt interativo para retornar". Exatamente!!! E o SSH não faz isso como esperado.
user4674453
1

Deve ser o suficiente para encontrar um caminho para killo catcomando.
Para as propostas a seguir, você pode precisar de uma segunda conexão ssh aberta.

  • Raramente CTRL+zpode ser mais eficaz do que CTRL+c: pode responder mais rapidamente. Depois que você suspender o comando, poderá matá-lo com kill %1ou qualquer que seja o número do trabalho.
    Isso na esperança de que você ainda consiga ler qualquer coisa na tela (um texto binário aleatório pode inundar facilmente seu conjunto de caracteres).
    Como lembrado por Gilles, se você minimizar a janela, provavelmente o sistema será mais rápido para ler a solicitação de interrupção do que para matar o processo. Portanto, suspender / interromper, minimizar, esperar um pouco, maximizar novamente, também pode ser uma solução.
    Obviamente, através de uma conexão ssh, espero que você precise esperar um pouco.

  • Em outro terminal / sessão, você pode perguntar pgrep cat(se o comando cat foi chamado) e identificar o processo do gato usando mais sua CPU. Você pode identificá-lo com mais precisão com pstree:

    gato pgrep | awk '{print "pstree -sp" $ 1}' | sh | grep sshd

    responda com uma saída como

    O problema é que o problema não é o problema, mas o problema é o seguinte: `` O problema é que o problema não foi resolvido ''.

    Nesse caso, depois que você tiver apenas que matar o gato PID: mate 23131

Nota:

Hastur
fonte
1

Eu tinha o mesmo problema e não estava satisfeito com as respostas aqui, então me aprofundou mais. Outros já mencionaram que seu comando está produzindo dados mais rapidamente do que o ssh pode suportar, portanto, os buffers de dados e os buffers não podem ser parados.

Para corrigir isso, evite armazenar em buffer limitando sua saída de comando para a taxa máxima que sua sessão ssh pode executar, já existem comandos para fazer isso.

Configuração, primeiro descubra a taxa máxima de suas sessões:

# Get transfer <TIME> of a large file (>10MB preferable)
/usr/bin/time -f "%e" cat <FILENAME>

# Get file <SIZE> in bytes
stat --printf="%s\n" <FILENAME>

# Calculate <RATE>
echo "<SIZE> / <TIME>" | bc

Finalmente, estrangule seus comandos reais de acordo.

<YOUR_COMMAND> | pv -qL <RATE>

Exemplo:

/usr/bin/time -f "%e" cat large_reference_file.txt
31.26

stat --printf="%s\n" cat large_reference_file.txt
17302734

echo "17302734 / 31.26" | bc
553510

# Throttle my command to 553510B/s
cat some_other_file.txt | pv -qL 553510

Você pode reduzir um pouco a TAXA caso a velocidade da sua conexão caia um pouco de tempos em tempos. Se cair, o comportamento retornará ao problema, um ctrl-c não responsivo.

Alias ​​de gato otimizado opcional:

# bash
alias tcat='tcat(){ cat $@ | pv -qL 400k ; }; tcat'

# tcsh
alias tcat 'cat \!* | pv -qL 400k'

# usage: tcat <FILENAME>

Agora, o ctrl-c funciona como esperado, eliminando imediatamente a saída, já que muito pouco ou nenhum é armazenado em buffer.

Eric
fonte
catA saída raramente está sendo um problema, diferente de outros softwares. O autor o usou apenas como exemplo. O problema geralmente ocorre devido a outro software, que pode não ser óbvio se estiver disposto a produzir muita saída. Usar qualquer tipo de comando prefixo ou postfix não é solução, pois leva tempo para digitá-lo. Não haverá nenhum ganho no resultado.
user4674453 4/09
0

Existe um software no Linux que resolve exatamente esse problema (algumas outras coisas também). Você também pode invocá-lo em um emulador de terminal no Windows (você parece estar usando o Windows?).

Tente mosh , um substituto para o binário SSH. Funciona exatamente como o SSH (você pode fazer em mosh user@hostnamevez de ssh user@hostnamee funcionaria exatamente como o esperado, fará até autenticação de chave privada etc.

Basicamente, ele executa um processo separado no servidor que armazena em buffer os pacotes. Portanto, quando você pressiona Ctrl + C no mosh, ele o transmite ao servidor remoto, que interrompe o envio de informações extras. Além disso, ele também prevê o resultado do pressionamento de tecla, economizando alguns milissegundos toda vez que você pressiona uma tecla.

Desvantagem: atualmente não é possível rolar para cima no histórico enquanto estiver usando o mosh.

Saksham Sharma
fonte