Команда ssh несподівано продовжується в іншій системі після припинення ssh


11

Я запускаю команду нижче та відслідковую вихідний файл в іншій системі:

ssh $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

Якщо я вбиваю команду ssh за допомогою ^Cабо просто вбиваю термінал, на який я ввійшов, я також очікую, що віддалена команда також припиниться. Однак цього не відбувається: /tmp/countотримує всі числа 1–5 незалежно і ps -ejHпоказує оболонку та її sleepдитина продовжує працювати.

Це очікувана поведінка і чи це документально десь зафіксовано? Чи можу я його відключити? Почитавши навколо, я очікував, що я повинен мати можливість чітко включити таку поведінку з nohup, не для того, щоб це було типовим.

Я переглянув сторінки man для ssh та sshd, але не помітив нічого очевидного, і Google вказує мені на вказівки щодо вмикання такої поведінки, а не для її вимкнення.

У мене працює Red Hat Enterprise Linux 6.2, з кореневим входом та оболонкою bash в обох системах.

Відповіді:


11

Відповідь утера говорить про те, щоб виділити термінал, але не пояснює, чому. Причина не характерна для ssh, це питання генерації та поширення сигналу. Запрошую вас прочитати Що викликає надсилання різних сигналів? для отримання додаткової інформації.

На віддаленому хості є два релевантні процеси:

  • екземпляр демона ssh ( sshd), який передає вхід і вихід віддаленої програми на локальний термінал;
  • оболонку, яка виконує цю forпетлю.

Оболонка може загинути або природним шляхом, коли вона досягне кінця петлі або зазнає фатальної помилки, або до сигналу. Питання в тому, чому оболонка отримає сигнал?

Якщо віддалена оболонка підключена до sshdтруб, це те, що відбувається, коли ви вкажете команду в sshкомандному рядку, вона загине від SIGPIPE, якщо sshdвийде, і оболонка намагатиметься записати в трубу. Поки оболонка не записує на трубу, вона не отримає ПІДПИС. Тут оболонка ніколи нічого не записує до свого стандартного виводу, тому може жити вічно.

Ви можете передати -tопцію ssh, наказати їй емулювати термінал на віддаленій стороні та виконати вказану команду в цьому терміналі. Потім, якщо клієнт SSH зникає, sshdзакриває з'єднання і виходить, руйнуючи термінал. Коли термінальний пристрій відходить, будь-який процес, що працює в ньому, отримує SIGHUP . Отже, якщо ви вбиваєте клієнта SSH (з killабо закриваючи термінал, на якому працює клієнт), віддалена оболонка буде SIGHUPped.

Якщо ви передаєте цей -tпараметр, SSH також ретранслює SIGINT . Якщо натиснути Ctrl+ C, то віддалена оболонка отримує SIGINT.


Використовуйте -ttзамість того, щоб, -tякщо сам ssh не виділив tty. SSH не отримає виділений tty, якщо ssh буде фоновим одразу після виклику через параметри типу -fабо -n.
Мірон V

3

Спробуйте виділити psuedo-tty за допомогою своєї sshкоманди.

ssh -t $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

Коли ви від'єднаєте сеанс ssh, процес повинен припинитися.

Оскільки це псевдо-tty, ініціалізація вашої оболонки, ймовірно, не збирається в вихідні файли конфігурації, залишаючи вашу команду з дуже голим середовищем. Можливо, вам знадобиться налаштувати .ssh/environmentфайл, який визначає змінні середовища, такі як PATH. Зman 1 ssh

Additionally, ssh reads ~/.ssh/environment, and adds lines of the format 
“VARNAME=value” to the environment if the file exists and users are allowed
to change their environment.  For more information, see the 
PermitUserEnvironment option in sshd_config(5).

2

Як альтернатива використанню -tопції, щоб sshзмусити віддалену команду припинятись, коли sshклієнт виходить або (вбивається), іменований канал може бути використаний для перетворення "EOF в SIGHUP", коли stdin of sshdзакривається (див. Bug 396 - sshd сироти відростають, коли не виділено жодного pty ).

# sample code in Bash
# press ctrl-d for EOF
ssh localhost '
TUBE=/tmp/myfifo.fifo
rm -f "$TUBE"
mkfifo "$TUBE"
#exec 3<>"$TUBE"

<"$TUBE" sleep 100 &  appPID=$!

# cf. "OpenSSH and non-blocking mode", 
# http://lists.mindrot.org/pipermail/openssh-unix-dev/2005-July/023090.html
#cat >"$TUBE"
#socat -u STDIN "PIPE:$TUBE"
dd of="$TUBE" bs=1 2>/dev/null
#while IFS="" read -r -n 1 char; do printf '%s' "$char"; done > "$TUBE"

#kill -HUP -$appPID 
kill $appPID

rm -f "$TUBE"
'

1

Це найкращий спосіб, який я знайшов для цього. Ви хочете щось на стороні сервера, що намагається прочитати stdin, а потім вбиває групу процесів, коли це не вдалося, але ви також хочете stdin на стороні клієнта, який блокує, поки процес серверної сторони не буде виконаний і не залишить затяжних процесів, як <( сон нескінченності) може.

ssh localhost "sleep 99 < <(cat; kill -INT 0)" <&1

Він насправді не здається перенаправляти stdout куди завгодно, але він функціонує як блокуючий вхід і уникає фіксації натискань клавіш.

Відповідна помилка opensh: https://bugzilla.mindrot.org/show_bug.cgi?id=396#c14


0

Якщо ви хочете відключити це (здавалося б, поведінка за замовчуванням), вам потрібно включити ssh-Keep-Live на клієнті або сервері.

Якщо ви подивитеся параметри ssh-Keep-Live на підручних сторінках, то зможете побачити, що вони відключені за замовчуванням.


0

Моя відповідь заснована на тері. Мені потрібен помічник сценарію ~/helperна сервері server.ip:

#!/bin/bash
TUBE=/tmp/sshCoLab_myfifo.$$;
mkfifo "$TUBE"
( <"$TUBE" "$@" ; rm "$TUBE" ; kill -TERM 0 ) &  
cat >"$TUBE" ;
rm "$TUBE" ;
kill -TERM 0 ;

Якщо воно називається, наприклад, з

ssh server.ip ~/helper echo hello from server

і виконується echo hello from serverна server.ip, а потім ssh-клієнт припиняється.

Якщо воно називається, наприклад, з

ssh server.ip ~/helper sleep 1000 &
CHID=$!

kill -9 $CHIDтакож зупинить скрипт на сервері. Для мене kill -INT $CHIDце не працює, але я не знаю чому.

Відповідь teru, команда ssh буде чекати вічно, коли віддалена команда буде закінчена, тому що catніколи не закінчується.

Усі відповіді з ssh -t у мене не працювали kill, а лише з Ctrl-C.

Редагувати: я дізнався, що це працювало від нового Ubuntu 14.01 до старшої наукової скриньки Linux - але не навпаки. Таким чином, я думаю, загального рішення немає. Дивно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.