объяснение
Дело не в 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
) должен быть выполнен.