
Я пытаюсь автоматизировать несколько распространенных задач, которые я выполняю по SSH на удаленном сервере. Для этого я использую PuTTY и его опцию "удаленная команда" (Подключение > SSH) в нескольких сохраненных сеансах. Моя удаленная команда выглядит примерно так:
~/scripts/test; $SHELL -l
Выполняемый скрипт отличается для каждого сохраненного сеанса и выполняет разные задачи. $SHELL -l
сохраняет сеанс PuTTY активным после завершения выполнения скрипта.
Все это прекрасно работает для большинства скриптов, которые я запускаю. Однако у меня есть один, который использует цикл while для выполнения серии команд, пока он не будет завершен с помощью Ctrl+C. Скрипт запускается нормально, но оболочка PuTTY не остается активной после его завершения. $SHELL -l
не похоже, что он выполняется.
Пример сценария с таким поведением выглядит следующим образом:
while true; do
echo "."
sleep 2
done
Следующий код отлично работает при ручном выполнении, я вижу ожидаемый вывод от второй команды:
~/scripts/test; echo "done"
Однако вторая команда PuTTY "remote command" не выполняется. Действительно, если я изменю удаленную команду, включив echo
, она не отобразится.
~/scripts/test; echo "done"; $SHELL -l
Итак, я думаю, мой вопрос: почему вторая команда в списке не выполняется удаленной командой, хотя выполняется вручную? И, что еще важнее, что я могу с этим сделать?
Если это актуально, я использую PuTTY на Ubuntu 14.04.
решение1
Когда вы запускаете putty
или ssh
— я не думаю, что в этом контексте есть какая-либо разница — команду для запуска на удаленной системе, удаленный сервер SSH запускает команду как команду оболочки:
/bin/bash -c '~/scripts/test; $SHELL -l'
Итак, у вас есть bash
экземпляр на удаленной системе, выполняющий этот конвейер. У вас также есть другой bash
экземпляр, запущенный первым экземпляром, выполняющий этот "тестовый" скрипт.
При нажатии Control-C putty
символ отправляется на удаленную систему, где он интерпретируется вашим TTY как символ прерывания. Это приводит к отправке SIGINT (сигнала прерывания) процессам, которые подключены к TTY. Это прерывает оба этих процесса оболочки, заставляя их оба завершиться. Вы хотите, чтобы родительский экземпляр оболочки игнорировал SIGINT.
Команда bash для игнорирования SIGINT:
trap "" INT
Таким образом, чтобы отключить SIGINT для вашего конвейера, вам нужно изменить исходную команду на:
trap '' INT; ~/scripts/test; $SHELL -l
Но это отключает SIGINT также и для дочерних процессов, что сделает "тестовый" скрипт невосприимчивым к Ctrl-C. Поэтому вам нужно снова включить SIGINT для тестового скрипта. Команда для этого:
trap INT
Эту строку можно добавить в сам тестовый скрипт или в конвейер:
trap '' INT; ( trap INT; ~/scripts/test ); $SHELL -l
Теперь, когда вы нажмете Ctrl-C, вы должны прервать процесс «теста», но не родительский процесс, который выполняет командный конвейер.
Вы можете проверить это без использования putty или ssh. Просто запустите эти команды и попробуйте нажать Ctrl-C во время выполнения "sleep":
bash -c 'sleep 15; echo foo' # Ctrl-C kills sleep; doesn't print "foo"
bash -c 'trap "" INT ; sleep 15; echo foo' # Ctrl-C has no effect
bash -c 'trap "" INT; ( trap INT; sleep 15 ); echo foo' # Kills sleep, prints "foo"
решение2
ctrl+c для удаленной команды putty фактически прерывает сеанс ssh, поэтому следует ожидать, что он не выполнит оставшиеся удаленные команды. Если ваша цель — просто сохранить сеанс активным, то вашего бесконечного цикла должно быть достаточно.