Почему SSH -t не ждет фоновых процессов?

13

Почему это ssh -tне ждет завершения фоновых заданий?

Пример:

ssh user@example 'sleep 2 &'

Это работает как ожидалось, так как ssh возвращается через 2 секунды, тогда как

ssh user@example -t 'sleep 2 &'

не ждет sleepокончания и сразу возвращается.

Кто-нибудь может объяснить причину этого? Можно ли ssh -tдождаться завершения всех фоновых процессов, прежде чем вернуться?

Мой вариант использования заключается в том, что я запускаю сценарий ssh -t, и этот сценарий запускает несколько фоновых заданий, которые должны остаться в живых после завершения основного сценария. С ssh -tэтим пока невозможно.

Филипп Мерри
источник

Ответы:

22

Без -t, sshdполучает stdout удаленной оболочки (и дочерних, как sleep) и stderr через два канала (а также отправляет входные данные клиента через другой канал).

sshd ожидает процесс, в котором он запустил оболочку входа пользователя, но также и после того, как этот процесс завершился, ожидает eof на канале stdout (по крайней мере, на канале stderr в случае openssh).

И eof происходит, когда файловый дескриптор любого процесса, открытого на конце записи канала, отсутствует, что обычно происходит только тогда, когда все процессы, чей stdout не перенаправлен на что-то другое, пропали.

Когда вы используете -t, sshdне использует трубы. Вместо этого все взаимодействие (stdin, stdout, stderr) с удаленной оболочкой и ее дочерними элементами выполняется с использованием одной псевдо-терминальной пары.

С псевдо-терминальной парой для sshdвзаимодействия со стороной мастера нет аналогичной обработки eof или какого-либо способа узнать, существуют ли еще процессы с открытыми fds для ведомой стороны псевдотерминала, поэтому он просто ожидает завершения процесс, в котором он выполнил оболочку входа удаленного пользователя и затем завершил работу.

После этого выхода главная сторона пары pty закрывается, что означает, что pty уничтожен, поэтому процессы, управляемые ведомым, получат SIGHUP (который по умолчанию завершит их).

Стефан Шазелас
источник
1
спасибо за подробный ответ! еще одна вещь, которую я хотел бы знать: все ли фоновые процессы завершаются после выхода из псевдотерминала? скрипт, который я запускаю, запускает сервис, который хорошо работает с ssh. но при использовании ssh -t служба не запускается. Похоже, что служба закрывается, когда ssh возвращается.
Филипп Мерри
На самом деле, для главной стороны псевдотерминала есть способ узнать, когда все дескрипторы подчиненных файлов были закрыты. Это тот же механизм, который запускается реальным терминалом, когда все файловые дескрипторы к нему фактически закрыты.
JdeBP
@JdeBP, ты хочешь расширить? Я не уверен, что вы имеете в виду. Эмуляторы терминала AFAICT (по крайней мере, xterm и gnome-терминал) не заботятся о процессах, у которых fds открыт для ведомого, когда процесс, в котором они выполнили оболочку, умирает
Стефан
@PhilippMurry Вы можете использовать, nohupчтобы скрипт работал так. (Вы можете также рассмотреть возможность запуска длительных заданий внутри, tmuxчтобы вы могли отслеживать их прогресс в интерактивном режиме, но файл журнала работает нормально.)
jpaugh
5

Используйте wait:

ssh user@example -t 'sleep 2 & wait'
Ипор Сирсер
источник