Создайте подоболочку для SSH и продолжите выполнение программы

Я пытаюсь написать сценарий оболочки, который автоматизирует определенные задачи запуска в зависимости от моего местоположения (дом/кампусA/кампусB). Я учусь в университете и посещаю занятия в двух разных кампусах (отсюда кампус A/кампус B). Мое местоположение определяется тем, к какой беспроводной сети я подключен. Для целей этого сценария мы можем предположить, что я буду подключен к одной из этих сетей при вызове сценария, и мой сценарий знает, к какой из них я подключен, на основе вызова iwconfig.

Вот что я хочу сделать:

cat file1 > file2 # always do this, regardless of where I am
if Im at home:
    start tweetdeck, thunderbird, skype

else if Im at campusA:
    activate the login script # I need to login on a webform before I get internet access. 
                              # I have written a script to automate this. 
                              # Wait for this script to finish before doing anything else
    myProg2 & # I want myProg2 running in the background until I shutdown my computer.

else if Im at campusB:
    ssh username@domain # this is the problematic line
    myProg2 & # I want myProg2 running in the background until I shutdown my computer.

start tweetdeck, thunderbird
close the terminal with the "exit" command

Проблема в том, что беспроводная сеть campusB находится за брандмауэром, который предоставляет мне доступ в Интернет ТОЛЬКО после того, как я успешно подключился по ssh с помощью username@domain. После успешного ssh мне нужно держать окно терминала активным, чтобы сохранить доступ в Интернет. Если я закрою окно терминала, я потеряю доступ в интернет (это плохо).

Когда я пытаюсь выполнить только ssh username@domain, сценарий останавливается, потому что я не завершаю команду ssh. Я не могу ^C выйти из него, а это значит, что остальная часть скрипта никогда не выполняется. У меня также возникает та же проблема, если я просто закрываю окно терминала, пытаясь завершить сеанс ssh.

Некоторое гугление привело меня к subshell, который я либо использую неправильно, либо не могу. не использовать для решения моей проблемы. Итак, как мне решить эту проблему? Буду признателен за любую помощь - я уже некоторое время занимаюсь этим и не могу найти ничего полезного. Если это имеет значение, я бы предпочел не хранить свой ssh пароль в скрипте.

Кроме того, амперсандирование вызова ssh (ssh username@domain &), похоже, не приносит никакой пользы (кто-нибудь может объяснить, почему?)

заранее спасибо

ИЗМЕНИТЬ

Я должен уточнить, что ssh-соединение должно быть активным, чтобы у меня был доступ в Интернет. Таким образом, когда я закрываю окно терминала, мне нужно, чтобы ssh-соединение оставалось активным.


person inspectorG4dget    schedule 03.03.2011    source источник
comment
ву-ху! Спасибо. Я не смотрел на это некоторое время. Здесь есть много других хороших ответов. Не стесняйтесь принимать лучшее, так как есть несколько хороших объяснений, которые я все еще не мог дать. Всем удачи!   -  person shellter    schedule 04.02.2014


Ответы (7)


У меня был скрипт, который зацикливался на 6 серверах, звоня по ssh в фоновом режиме. В 1 части скрипта было неправильное поведение приложения поставщика; приложение не «отпускало» соединение должным образом. (другие части скрипта, использующие ssh в фоновом режиме, работали нормально).

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

Надеюсь это поможет.

person shellter    schedule 04.03.2011
comment
Пожалуйста, скажите своему товарищу по команде, что он ПОТРЯСАЮЩИЙ. Если бы я мог дать больше повторений (после принятия и +1) за этот ответ, я бы это сделал. - person inspectorG4dget; 08.03.2011

Вы можете попытаться удвоить фон myProg2, чтобы отсоединить его от tty:

# cf. "Wizard Boot Camp, Part Six: Daemons & Subshells",
# http://www.linux-mag.com/id/5981
(myProg2 &) &

Другим вариантом может быть использование инструмента демона из пакета libslack:

http://ingvar.blog.linpro.no/2009/05/18/todays-sysadmin-tip-using-libslack-daemon-to-daemonize-a-script/

person gerd    schedule 04.03.2011
comment
Двойной фон работает, поскольку запрашивает пароль. Я не могу сохранить соединение после выхода из оболочки. Сначала мой вопрос не был очень ясен (я только что понял), поэтому я уточнил это в редактировании. - person inspectorG4dget; 08.03.2011
comment
+1 за то, что познакомил меня с демонизацией. Это научило меня чему-то новому, хотя это не то решение, которое мне нужно - person inspectorG4dget; 08.03.2011

Наличие ssh с псевдотерминалом на фоновой оболочке

В дополнение к ответу @shellter я хотел бы уточнить:

где @shelter сказал:

Справочная страница нашей системы не давала никаких намеков на то, что такое возможно

В моей системе (Debian 7 GNU/Linux) , если я нажму:

man -Pcol\ -b ssh| grep -A3 '^ *-t '

Я мог прочитать:

     -t      Force pseudo-tty allocation.  This can be used to execute arbi‐
             trary screen-based programs on a remote machine, which can be
             very useful, e.g. when implementing menu services.  Multiple -t
             options force tty allocation, even if ssh has no local tty.

Да: Несколько опций -t принудительно выделяют tty, даже если ssh не имеет локального tty.

Это означает: если вы удаленно запускаете инструмент, которому требуется доступ к pseudo terminal (pty, например /dev/pts/0), вы можете запустить его с помощью переключателя -t.

Но это будет работать только в том случае, если ssh запускается из консоли оболочки (т. е. с собственным pty). Если вы планируете запускать их в сеансе оболочки без консоли, например фоновых скриптах, вы можете использовать Несколько -t для принудительного выделения псевдотерминала из ssh.

Несколько оболочек ssh на одном ssh-соединении

В дополнение к ответам от @tommy и @geekosaur я бы сделал некоторую точность:

@tommy указывает на очень интересную особенность ssh. Не уверен, что это как-то связано с ответом, но, говоря о давнем соединении, эту функцию нужно четко понимать.

Как только соединение установлено, ssh может (и знает, как) использовать их для управления многими вещами в этом одном соединении:

  • -L позволяет управлять удаленными TCP-соединениями с локальными машинами/сетью. (полный синтаксис: -L localip:localport:distip:distport), где localip может быть указан, чтобы разрешить другим хостам из того же локального домена доступ к той же привязке tcp, а distip может быть любым хостом из удаленной сети (не только localhost ) пример: -L192.168.1.31:8443:google.com:443 разрешить любому хосту из локального домена подключаться к google через ваш хост: http://192.168.1.31:8443

  • -R Те же замечания в обратном порядке!

  • -M Скажите ssh, чтобы он открыл локальный сокет unix для привязки следующих консолей ssh. Просто откройте два окна терминала. Сначала в обоих окнах нажмите: ssh somewhere, затем нажмите netstat -tan | grep :22 или netstat -tan | grep 192.168.1.31:22 (при условии, что 192.168.1.31 — это IP-адрес вашего внешнего хоста)

    Затем сравните, закройте все ваши сеансы ssh и в первом терминале нажмите: ssh -M somewhere, а во втором просто ssh somewhere. вы можете увидеть во втором терминале:

    $ ssh somewhere
    + ssh somewhere
    Last login: Mon Feb  3 08:58:01 2014 from elsewhere
    

    Если теперь вы нажмете netstat -tan | grep 192.168.1.31:22 (в любом из двух открытых сеансов ssh;), вы должны увидеть, что существует только одно соединение tcp.

    Такого рода функции можно использовать в сочетании с -L и, возможно, некоторыми sleep 86399...

    Чтобы обойти маршрутизатор-убийцу tcp, который закрывает каждое неактивное TCP-соединение более 120 секунд, я запускаю:

    ssh -M somewhere 'while :;do uptime;sleep 60;done'
    

    Это гарантирует, что соединение останется, даже если я не нажму клавишу более двух минут.

person F. Hauri    schedule 03.02.2014
comment
Игра с экраном может помочь понять многое, связанное с псевдотерминалом... - person F. Hauri; 03.02.2014

Вот несколько мыслей, которые могут помочь.

Вложенные оболочки

Вложенные оболочки разветвляют новые процессы, но не возвращают управление вызывающей оболочке. Если вы хотите создать вложенную оболочку, которая сделает всю работу за вас, вам нужно будет добавить & к строке.

(ssh username@domain) &

Но это не выглядит веской причиной для использования подоболочки. Если бы у вас было несколько команд, которые вы хотели бы выполнять по порядку друг от друга, но параллельно из вызывающей оболочки, то, возможно, это того стоило бы. Например...

(dothis.sh; thenthis.sh; andthislastthingtoo.sh) &

Разветвление

Я не уверен, почему & у вас не работает, но, возможно, стоит изучить nohup тоже. Это делает команду «невосприимчивой» к зависанию сигналов.

nohup ssh username@domain (попробуйте с & в конце и без него)

Пароли

Не хранить пароли в сценарии необходимо для любой автоматизации ssh. Вы можете сделать это, используя криптографию с открытым ключом, которая является неотъемлемой особенностью ssh. Я не буду вдаваться в подробности здесь, потому что есть номер of отличные ресурсы по всему интернету по настройке. Я настоятельно рекомендую исследовать это дальше.

Если вы пойдете по этому пути, я также предлагаю запустить ssh в «пакетном режиме», который отключит запрос пароля и автоматически отключится от сервера, если он перестанет отвечать через 5 минут.

ssh -o 'BatchMode=yes' username@domain

Постоянство

Затем, если вы хотите сохранить соединение, запустите какой-нибудь глупый цикл в bash! :)

ssh -o 'BatchMode=yes' username@domain "while (( 1 == 1 )); do sleep 60; done"

person perden    schedule 03.03.2011
comment
Во всех этих случаях я могу ввести свой пароль, но соединение ssh не сохраняется. Мне нужно, чтобы соединение было активным, чтобы иметь доступ к Интернету - вход в систему только один раз не дает мне доступа (я понял, что мой вопрос не был ясен, и внес изменения, чтобы уточнить это). - person inspectorG4dget; 08.03.2011
comment
Если вам нужна настойчивость, вы можете попробовать запустить глупый цикл... :) Я обновил свой ответ, но, похоже, вы нашли то, что искали! - person perden; 09.03.2011
comment
+1 @perden за то, что заставил его работать, но это кажется гораздо более хакерским, чем должно быть - person inspectorG4dget; 10.03.2011
comment
Хороший ответ, но почему вы запутали список литературы!? - person F. Hauri; 03.02.2014

Проблема с & заключается в том, что ssh теряет доступ к своему стандартному вводу (терминал), поэтому, когда он начинает читать что-то для отправки другой стороне, он либо получает ошибку и завершает работу, либо система kill обрабатывается с помощью SIGTTIN, что неявно приостановить его. Для этого используются параметры -n и -f: -n говорит не использовать стандартный ввод, -f говорит настроить все необходимые туннели и т. д., а затем закрыть поток терминала.

Так что лучший способ сделать это, вероятно, сделать

ssh -L 9999:localhost:9999 -f host & # for some random unused port

а затем вручную убить ssh перед выходом из системы. Поочередно,

ssh -L 9999:localhost:9999 -n host 'while :; do sleep 86400; done' </dev/null &

(Перенаправление должно гарантировать, что SIGTTIN все равно не произойдет.)

Пока вы это делаете, вы можете сохранить идентификатор процесса и закрыть его из своего .logout/.bash_logout:

ssh -L 9999:localhost:9999 -n host 'while :; do sleep 86400; done' < /dev/null & echo $! >~.ssh_pid; chmod 0600 ~/.ssh_pid

и в .bash_logout:

if test -f ~/.ssh_pid; then
  set -- $(sed -n 's/^\([0-9][0-9]*\)$/\1/p' ~/.ssh_pid)
  if [ $# = 1 ]; then
    kill $1 >/dev/null 2>&1
  fi
  rm ~/.ssh_pid
fi

Дополнительный код пытается избежать того, чтобы кто-то саботировал ваш ~/.ssh_pid, потому что я профессиональный параноик.

(Код не проверен и может содержать опечатки)

person geekosaur    schedule 04.03.2011
comment
Этот ответ мне интересен. Не могли бы вы подробно объяснить, что делает ssh -L 9999:localhost:9999 -f host &? Кроме того, будет ли в этом коде замена host на user@domain работать так, как я ожидал? - person inspectorG4dget; 08.03.2011
comment
Параметр -L local:host:remote указывает ssh прослушивать порт local на локальном хосте и перенаправлять любые подключения к нему на удаленный sshd, чтобы открыть соединение с host через порт remote. Чаще всего host это localhost. Параметр -f сообщает ssh, что он только выполняет переадресацию портов, поэтому не запускайте команду и не запускайте сеанс. (Возможно, все еще потребуется фиктивная команда, такая как sleep 30, чтобы удерживать туннель достаточно долго, чтобы что-то могло к нему подключиться.) - person geekosaur; 08.03.2011

Прошло некоторое время с тех пор, как я использовал ssh, и я не могу проверить это прямо сейчас, но вы пробовали переключатель -f?

ssh -f username@domain

На справочной странице написано, что он поддерживает ssh. Не уверен, почему & не сработает, но я предполагаю, что он интерпретирует это как команду, которую нужно запустить на удаленной машине.

person OpenSauce    schedule 03.03.2011
comment
ssh -f не работает, потому что я в конечном итоге закрываю терминал. Похоже, что ssh не работает должным образом. Так что связь не сохраняется. - person inspectorG4dget; 08.03.2011
comment
@ InspectorG4dget У меня та же проблема, что -f не работает должным образом в фоновом режиме ssh и не позволяет мне закрыть терминал, хотя это должно работать. Вы когда-нибудь узнавали, почему? - person Adrian Frühwirth; 10.10.2013
comment
@AdrianFrühwirth: я так и не понял, почему, но в принятом ответе в этой теме есть решение, которое мне помогло. - person inspectorG4dget; 10.10.2013

Может быть, экран + ssh тоже подойдет?

Что-то типа:

screen -d -m -S sessionName cmd

screen -d -m -S sessionName cmd &

# reconnect with
screen -r sessionName
person tommy    schedule 11.03.2011