Explicação
Não é sobre wait
. Eu acho que é isso que acontece:
Você usa <<
, então stdin
de ssh
é redirecionado para algum descritor através do qual todo o documento aqui flui.
Esta outra resposta explica como ssh
é capaz de capturar Ctrl + C quando -t
é usado. Isso é o que importa:
On the client side,
ssh
will try to set thetty
used bystdin
to "raw" mode […] Setting raw mode means that characters that would normally send signals (such as Ctrl+C) are instead just inserted into the input stream.
No seu caso, não é o mesmo que stdin
dos seus usos locais de shell. tty
usado pelo seu shell local é deixado intacto, nunca é definido para o modo "raw".
Então quando você apertar Ctrl + C ele age localmente e termina ssh
. Neste momento, o lado remoto recebe SIGHUP
. Seu trap
funciona e mata java
. Eu acho que há uma armadilha aqui: um trap
executa algum código em resposta a um dado sinal, mas não impede que o sinal tenha seu efeito normal. Portanto, parece-me que seu java
seria eliminado mesmo sem um trap
, porque é um trabalho do shell que é finalizado em resposta a SIGHUP
.
O shell que é terminado pára de ler e interpretar seu stdin
. É por isso que tudo que segue wait
é descartado.
Solução
commands() { cat <<-'COMMANDS'
cleanup() {
# cleanup code here
echo "Done. Logging out"
sleep 2
logout
}
echo "Preparing execution"
java -jar execute.jar &
executePID=$!
echo "Ready."
echo "CTRL+C to clean and close"
trap "kill $executePID; cleanup" INT HUP
wait $executePID
cleanup
COMMANDS
}
stty raw -echo; cat <(commands) - | ssh -t [email protected]; stty -raw echo
A última linha é o comando atual. Primeiro nós preparamos tty
então Ctrl + C não pode atuar localmente. Então nós concatenamos os comandos e a entrada padrão, nós a passamos para o shell remoto. Eu não posso fazer isso com aqui documento diretamente, a função command
é uma solução alternativa (seria mais fácil usar um arquivo regular, mas você disse que não pode usar mais de um). Após ssh
e cat
sair, definimos o tty
para seu estado normal.
Ter um pseudo-terminal é essencial, portanto, certifique-se de que ssh -t
funcione (use -tt
, se necessário).
O shell remoto deve ler (buffer) todos os comandos de commands
, somente então ele pode obter Ctrl + C ao pressioná-lo. Eu acho que isso significa que você não pode ter muito código após wait
. Além disso, o que você quiser fazer depois de SIGINT
deve ser executado dentro do trap
. Estas são as razões pelas quais usei uma única função cleanup
que faz tudo.
O código não é infalível. Pressione Ctrl + C muito cedo ou várias vezes e você se encontrará no shell remoto ou com um pouco "quebrado" local tty
. Neste último caso, use o comando reset
para redefinir seu tty
.
Você deve pressionar uma tecla (por exemplo, Enter ) depois de ver "Conexão para ... fechado". A razão é que cat
não notará que o canal está quebrado (porque ssh
não está mais) até tentar escrever algo nele.
Alternativa
Se por algum motivo a solução acima não funcionar, use esta alternativa mais simples. O documento aqui é exatamente como antes. Neste caso, não mexemos com tty
, Ctrl + C termina local ssh
como acontece com o seu código original. A diferença (em relação ao seu código) é a trap
da limpeza. Eu acho que seria o suficiente para capturar apenas SIGHUP
.
ssh -t [email protected] <<-'COMMANDS'
cleanup() {
# cleanup code here
echo "Done. Logging out"
sleep 2
logout
}
echo "Preparing execution"
java -jar execute.jar &
executePID=$!
echo "Ready."
echo "CTRL+C to clean and close"
trap "kill $executePID; cleanup" INT HUP
wait $executePID
cleanup
COMMANDS
Observação: quando trap
for acionado, cleanup
exibirá uma mensagem, mas você não a verá porque seu ssh
local já está desconectado. Você verá a mensagem somente se java
sair sem o trap
. Ainda seu código de limpeza ( # cleanup code here
) deve ser executado.