Вопрос или проблема
Я могу выполнить команду:
cd /var/www/test; tail -f log/*.log;
на удаленном сервере через SSH, как:
ssh -t [email protected] "cd /var/www/test; tail -f log/*.log; exec $SHELL -l"
что прекрасно работает.
Но как только я нажимаю Control + C
, чтобы остановить команду, чтобы сделать что-то другое, соединение закрывается с сообщением
Соединение с xx.yy.zz.aa закрыто.
Как предотвратить это и оставаться подключенным даже после нажатия Control + C
?
Этого не должно происходить. ssh
должен отключать генерацию сигналов в терминале.
Вы можете попробовать перехватить SIGINT
в оболочке, которая вызывает ssh
trap '' SIGINT
но процессы на другой стороне тоже не получат сигнал.
Вы также можете попытаться отправить буквальный ^C
в ssh
, нажав
^V^C
^V
обычно является “экранирующим” символом для терминала. То есть вместо интерпретации ^C
как генерации сигнала, он просто передается как есть.
Я думаю, что могу точно объяснить, почему это происходит, и уверяю вас, что это ожидаемое поведение. Когда вы отправляете команду через ssh (ssh host ‘command’), вы на самом деле не входите на удаленный хост; вместо этого вы просто даете разрешение на выполнение команды там, и этот вывод возвращается в ваш локальный терминал.
Вы можете увидеть это в действии, запустив что-то более простое: ssh host ‘ls -al’
Вам будет предложено ввести свои учетные данные, удаленный хост выведет (в ваш терминал) содержимое запрашиваемого каталога, как если бы вы вошли напрямую, а затем (после завершения команды ls) вы вернетесь к своему локальному приглашению.
Это ключевой момент: как только удаленная команда завершается, вы возвращаетесь к своему локальному приглашению.
Ваш интересный выбор команды создал иллюзию, что вы действительно вошли в удаленную систему. (Хотя некоторые могут возразить против моего конкретного языка/лексики, суть правильна.)
Чтобы увидеть это в действии, попробуйте что-то более простое: ssh host ‘cat someTextFile.txt | less’
Это запустит less, где будет содержимое, которое вы запросили. Вы можете нажимать пробел до конца, если файл длинный. Less технически запускается на удаленном хосте, но как только вы наберете ‘q’, вы вернетесь к своему локальному приглашению. Вы возвращаетесь к своему локальному приглашению, как только команда less завершена.
Я надеюсь, что это поможет вам или кому-то, кто будет следить за этим.
Ответ или решение
Для решения задачи выполнения команды через SSH и предотвращения закрытия соединения при нажатии на Ctrl+C, следует понимать, как именно работает SSH и передача сигналов к процессам.
Когда вы выполняете команду через SSH (например, ssh user@host 'cd /var/www/test; tail -f log/*.log;'
), вы, по сути, запускаете удалённую команду и получаете вывод в своём терминале. При этом SSH не сохраняет постоянное соединение, поскольку команда tail -f
работает в фоновом режиме до тех пор, пока её не будет прервано. При нажатии на Ctrl+C сигнал SIGINT отправляется на этот процесс и приводит к завершению сессии, что и вызывает сообщение "Connection closed".
Решения проблемы:
-
Использование
nohup
:
Один из подходов заключается в использовании командыnohup
, которая игнорирует сигнал SIGHUP. В вашем случае команда может выглядеть так:ssh -t user@host "cd /var/www/test; nohup tail -f log/*.log > output.log 2>&1 &"
В этом случае процесс
tail
будет работать в фоновом режиме даже после отключения терминала. Однако, чтобы увидеть вывод текста, необходимо будет обратиться к файлуoutput.log
. -
Использование
screen
илиtmux
:
Использование терминальных мультиплексоров, таких какscreen
илиtmux
, является ещё одним отличным вариантом. Эти инструменты позволяют управлять множеством терминальных сессий и сохранять их даже если ваше соединение прерывается. Вот как это может быть сделано:ssh -t user@host "cd /var/www/test; screen -S logsession; tail -f log/*.log"
Или с использованием
tmux
:ssh -t user@host "cd /var/www/test; tmux new-session -s logsession 'tail -f log/*.log'"
После этого вы можете отсоединиться от сессии
screen
илиtmux
, нажавCtrl+A
затемD
дляscreen
илиCtrl+B
затемD
дляtmux
. Позже вы сможете вернуться в вашу сессию, используя командыscreen -r logsession
илиtmux attach -t logsession
. -
Траппинг сигнала SIGINT:
Если вы хотите просто перехватить сигнал и предотвратить закрытие соединения, вы можете использовать встроенную командуtrap
:ssh -t user@host "trap '' SIGINT; cd /var/www/test; tail -f log/*.log"
Однако это может привести к тому, что вы не сможете остановить
tail
с помощью Ctrl+C, так как сигнал будет игнорироваться.
Заключение:
Из практических соображений наиболее простым и надёжным способом будет использование screen
или tmux
. Эти инструменты позволяют вам сохранять сессии и легко возвращаться к ним, что значительно упрощает работу с длительными командами и процессами на удалённых серверах.