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,
sshwill try to set thettyused bystdinto "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.