
Estou tentando automatizar várias tarefas comuns que faço por SSH em um servidor remoto. Para isso, estou utilizando o PuTTY e sua opção de "comando remoto" (Conexão > SSH) em diversas sessões salvas. Meu comando remoto é mais ou menos assim:
~/scripts/test; $SHELL -l
O script executado difere por sessão salva e executa tarefas diferentes. $SHELL -l
mantém a sessão PuTTY ativa após o término da execução do script.
Tudo isso está funcionando perfeitamente para a maioria dos scripts que estou executando. No entanto, tenho um que usa um loop while para executar uma série de comandos até terminar com Ctrl+C. O script inicia bem, mas o shell PuTTY não permanece ativo depois de encerrado. $SHELL -l
não parece estar sendo executado.
Um exemplo de script com esse comportamento é o seguinte:
while true; do
echo "."
sleep 2
done
O seguinte funciona bem executado manualmente, vejo a saída esperada do segundo comando:
~/scripts/test; echo "done"
No entanto, o segundo comando do "comando remoto" do PuTTY não é executado. Na verdade, se eu alterar o comando remoto para incluir um echo
, ele não será exibido.
~/scripts/test; echo "done"; $SHELL -l
Então, acho que minha pergunta é: por que o segundo comando da lista não é executado pelo comando remoto, enquanto é executado manualmente? E, mais importante, o que posso fazer a respeito?
Se for relevante, estou executando o PuTTY no Ubuntu 14.04.
Responder1
Quando você executa putty
ou ssh
- não acho que haja alguma diferença neste contexto - com um comando para executar no sistema remoto, o servidor ssh remoto executa o comando como um comando shell:
/bin/bash -c '~/scripts/test; $SHELL -l'
Então você tem uma bash
instância no sistema remoto executando esse pipeline. Você também tem outra bash
instância, iniciada pela primeira instância, executando este script de “teste”.
Quando você digita Control-C, putty
envia o caractere para o sistema remoto, onde é interpretado pelo seu TTY como o caractere de interrupção. Isso resulta no envio de um SIGINT (sinal de interrupção) para processos que estão anexados ao TTY. Isso interrompe ambos os processos do shell, fazendo com que ambos sejam encerrados. Você deseja que a instância do shell pai ignore o SIGINT.
O comando bash para ignorar o SIGINT é:
trap "" INT
Portanto, para desabilitar o SIGINT para seu pipeline, você alteraria seu comando original para:
trap '' INT; ~/scripts/test; $SHELL -l
Mas isso também desativa o SIGINT para processos filhos, o que tornaria o script de "teste" imune a Ctrl-C. Portanto, você precisa reativar o SIGINT para o script de teste. O comando para isso é:
trap INT
Você pode adicionar essa linha ao próprio script de teste ou ao pipeline:
trap '' INT; ( trap INT; ~/scripts/test ); $SHELL -l
Agora, ao pressionar Ctrl-C, você deve interromper o processo de "teste", mas não o processo pai que está executando o pipeline de comando.
Você pode testar isso sem usar putty ou ssh. Basta executar estes comandos e tentar pressionar Ctrl-C enquanto o “sleep” está em execução:
bash -c 'sleep 15; echo foo' # Ctrl-C kills sleep; doesn't print "foo"
bash -c 'trap "" INT ; sleep 15; echo foo' # Ctrl-C has no effect
bash -c 'trap "" INT; ( trap INT; sleep 15 ); echo foo' # Kills sleep, prints "foo"
Responder2
ctrl+c para o comando remoto putty está na verdade interrompendo a sessão ssh, portanto, deve-se esperar que ele não execute os comandos remotos restantes. Se o seu objetivo é apenas manter a sessão ativa, apenas o seu loop infinito deve ser suficiente.