SSH + здесь документ - Ctrl + C добраться до удаленной стороны?

726
brunoais

Как часть серии задач, которые мне нужно выполнить, я должен создать сценарий bash, который обращается к удаленному компьютеру, выполняет 3 команды, ожидает завершения процесса через SIGINT(или просто завершается) и затем выполняет некоторую очистку.

В настоящее время я использую этот код:

#! /bin/bash  # local preparations # ...  ssh -t $USER@remote.far <<-'COMMANDS'  echo "Preparing execution"  java -jar execute.jar & executePID=$!  echo "Ready." echo "CTRL+C to clean and close"  trap "kill $executePID" INT HUP wait $executePID  #cleanup code here  echo "done. Logging out" sleep 2 logout COMMANDS  # Final local cleanup 

Этот код, кажется, работает только waitкоманда find (встроенная). waitкажется, потребляет все команды, которые идут после него, и поэтому, когда я пытаюсь отправить SIGINT( Ctrl+ C), кажется, что он не в состоянии выполнить содержимое прерывания и весь код очистки.

Как я могу это исправить, чтобы все работало так, как я ожидаю?

Мне не разрешено разбивать этот bash-файл на несколько, и мне не разрешается создавать какие-либо сценарии на удаленном компьютере, даже если они временные.
Оба компьютера работают под управлением Linux.

0
Что если вы переместите `wait $ executePID` вне команды ssh? Затем можно заменить $ executePID на PID команды ssh вместо команды Java. Кроме того, вы хотите сказать, что если вы выполните этот скрипт & ctrl-c, то вы хотите, чтобы он запускал некоторые дополнительные команды для очистки удаленного хоста? Если это так, то что вам нужно посмотреть на создание собственной функции обработки ловушек с использованием `trap ctrl_c INT`, а затем написание функции ctrl_c, которая будет вызываться при запуске SIGINT [см. Этот пост в блоге] (https: // rimuhosting .com / База знаний / Linux / разное / улавливать-Ctrl-C-в-Баш). stuts 7 лет назад 0
В дополнение к моим предыдущим комментариям, вы знаете, что сценарий определенно зависает в ожидании? Ваша команда java не запускает команду в фоновом режиме (заканчивая строку `&`), так что может случиться так, что ваш скрипт запускает процесс java, и именно здесь ctrl-c выполняет команду. Вы определенно видите эхо «Готово» и «CTRL-C» при выполнении сценария? stuts 7 лет назад 0
@stuts Извините за задержку. Я знаю, где он висит, потому что я сделал несколько выводов отладки в консоль для bash и отладку в файл для java-программы. CTRL- Cнаправляется на Java и программа Java завершает , как и ожидалось. Вы получили замечание о пропущенном `&` в этом примере скрипта. Я исправлю это. brunoais 7 лет назад 0

1 ответ на вопрос

1
Kamil Maciorowski

объяснение

Это не о wait. Я думаю, что это то, что происходит:

Вы можете использовать <<, поэтому stdinиз sshперенаправляется в какой - то дескриптор, через который весь документ здесь течет.

Этот другой ответ объясняет, как sshможно захватить Ctrl+, Cкогда -tиспользуется. Вот что важно:

На стороне клиента sshбудет пытаться установить ttyиспользуемый stdinрежим в «сырой» режим […]. Установка сырого режима означает, что символы, которые обычно посылают сигналы (например, Ctrl+ C), вместо этого просто вставляются во входной поток.

В вашем случае это не то же самое, что stdinваша локальная оболочка. ttyиспользуемая вашей локальной оболочкой остается без изменений, она никогда не устанавливается в «сырой» режим.

Поэтому, когда вы нажимаете Ctrl+, Cон действует локально и завершается ssh. В этот момент удаленная сторона получает SIGHUP. Твои trapработы и убийства java. Я думаю, что здесь есть подводный камень: a 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) должен быть выполнен.

Выглядит отлично! Спасибо! Я попробую, когда смогу, а потом постараюсь сообщить об этом. brunoais 6 лет назад 0

Похожие вопросы