Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: inspectorG4dgetОтветов: 7

Я пытаюсь написать сценарий оболочки, который автоматизирует определенные задачи запуска в зависимости от моего местоположения (дом/кампус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-соединение оставалось активным.

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

sshbash

Ответы

Ответ 1 · рейтинг 7 · shellter

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

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

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

Ответ 2 · рейтинг 2 · gerd

Вы можете попытаться удвоить фон 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/

Ответ 3 · рейтинг 2 · F. Hauri

Наличие 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'
    

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

Ответ 4 · рейтинг 2 · perden

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

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

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

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

Ответ 5 · рейтинг 1 · geekosaur

Проблема с & заключается в том, что 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, потому что я профессиональный параноик.

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

Ответ 6 · OpenSauce

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

ssh -f username@domain

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

Ответ 7 · tommy

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

Что-то типа:

screen -d -m -S sessionName cmd

screen -d -m -S sessionName cmd &

# reconnect with
screen -r sessionName

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы