объяснение
Дело не в wait . Я думаю, что это то, что происходит:
Вы используете << , поэтому stdin из ssh перенаправляется на некоторый дескриптор, через который проходит весь документ .
Этот другой ответ объясняет, как ssh может захватывать Ctrl+C при использовании -t . Вот что важно:
На стороне клиента ssh попытается установить tty используемый stdin в режим "raw" […]. Установка режима raw означает, что символы, которые обычно посылают сигналы (такие как Ctrl+C), вместо этого просто вставляются во входной поток.
В вашем случае это не то же stdin локального использования оболочки. tty используемый вашей локальной оболочкой, остается без изменений, он никогда не устанавливается в "сырой" режим.
Поэтому, когда вы нажимаете Ctrl+C, он действует локально и завершает работу ssh . В этот момент удаленная сторона получает SIGHUP . Ваша trap работает и убивает java . Я думаю, здесь есть подводный камень: trap выполняет некоторый код в ответ на данный сигнал, но не мешает нормальному эффекту сигнала. Поэтому мне кажется, что ваша java будет убита даже без trap потому что это работа оболочки, которая завершается в ответ на SIGHUP .
Завершенная оболочка прекращает чтение и интерпретацию своего стандартного stdin . Вот почему все, что следует за wait , отбрасывается.
Решение
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 $USER@remote.far; stty -raw echo
Последняя строка - фактическая команда. Сначала мы подготавливаем tty чтобы Ctrl+C не мог действовать локально. Затем мы объединяем команды и стандартный ввод, передаем его в удаленную оболочку. Я не могу сделать это с этим документом напрямую, command функция - это обходной путь (было бы проще использовать обычный файл, но вы сказали, что не можете использовать более одного). После выхода из ssh и cat мы устанавливаем tty в его нормальное состояние.
Наличие псевдотерминала очень важно, поэтому убедитесь, что ssh -t работает (при необходимости используйте -tt ).
Удаленная оболочка должна читать (буферизовать) все команды из commands , только тогда она может получить Ctrl+C, когда вы ее нажмете. Я думаю, это означает, что вы не можете иметь слишком много кода после wait . Кроме того, все, что вы хотите сделать после SIGINT должно быть запущено из trap . По этим причинам я использовал одну функцию cleanup которая делает все это.
Код не является надежным. Нажмите Ctrl+C слишком рано или несколько раз, и вы окажетесь в удаленной оболочке или с несколько "сломанным" локальным tty . В этом последнем случае используйте команду reset для сброса вашего tty .
Вы должны нажать клавишу (например, Enter) после того, как увидите «Соединение с… закрыто». Причина в том, что cat не заметит, что канал не работает (из-за того, что ssh больше не существует), пока не попытается что-то записать в него.
альтернатива
Если по какой-либо причине вышеуказанное решение не работает для вас, воспользуйтесь этой более простой альтернативой. Здесь документ точно такой же, как и раньше. В этом случае мы не связываемся с tty , Ctrl+C завершает локальный ssh как это происходит с вашим исходным кодом. Разница (по отношению к вашему коду) в том, что trap выполняет уборку. Я думаю, что этого будет достаточно, чтобы поймать только SIGHUP .
ssh -t $USER@remote.far <<-'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
Примечание: когда срабатывает trap cleanup выводит сообщение, но вы его не увидите, потому что ваш локальный ssh уже отключен. Вы увидите сообщение, только если java выйдет без trap . Тем не менее ваш код очистки (# cleanup code here) должен быть выполнен.