Я пытаюсь автоматизировать несколько общих задач, которые я выполняю по SSH на удаленном сервере. Для этого я использую PuTTY и его опцию "удаленная команда" (Connection> 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 "Удаленная команда" не выполняется. Действительно, если я изменю удаленную команду, чтобы включить echo , она не отображается.

~/scripts/test; echo "done"; $SHELL -l

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

Если это актуально, я запускаю PuTTY на Ubuntu 14.04.

2 ответа2

2

Когда вы запускаете 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, вы должны прервать процесс "test", но не родительский процесс, выполняющий конвейер команд.

Вы можете проверить это без использования putty или ssh. Просто запустите эти команды и попробуйте нажать Ctrl-C, пока выполняется "сон":

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"
0

Ctrl + C для удаленной команды putty фактически прерывает сеанс ssh, поэтому следует ожидать, что он не выполнит оставшиеся удаленные команды. Если ваша цель состоит в том, чтобы сеанс продолжал оставаться активным, вашего бесконечного цикла должно быть достаточно.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .