BASH создать подошву для SSH и продолжить с потоком программы
Я пытаюсь написать оболочку script, которая автоматизирует некоторые задачи запуска на основе моего местоположения (home/campusA/campusB). Я еду в университет и занимаюсь занятиями в двух разных университетских городках (следовательно, в кампусе A/campusB). Мое местоположение определяется, с какой беспроводной сетью я подключен. Для целей этого script мы можем предположить, что я буду подключен к одной из этих сетей при вызове script, а мой script знает, к какому я подключен, на основе вызова 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 [email protected] # 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 [email protected]
. После успешного ssh мне нужно, чтобы окно терминала было активным, чтобы удерживать доступ в Интернет. Если я закрою окно терминала, я потеряю доступ в Интернет (это плохо).
Когда я пытаюсь сделать только ssh [email protected]
, script останавливается, потому что я не выхожу из команды ssh
. Я не могу ^C
выйти из него, а это значит, что остальная часть script никогда не выполняется. У меня также такая же проблема, если я просто закрываю окно терминала, пытаясь убить сеанс ssh
.
Некоторые поисковики привезли меня в subshell
, который я либо неправильно использую, либо не могу использовать для решения моей проблемы. Итак, как мне решить эту проблему? Я был бы признателен за любую помощь - я был в этом какое-то время и не могу найти ничего полезного. Если это имеет значение, я бы предпочел не хранить мой пароль ssh
в script
Кроме того, амперсандинг вызова ssh
(ssh [email protected] &
), похоже, не приносит пользы (может кто-нибудь объяснить, почему?)
Заранее благодарю
ИЗМЕНИТЬ
Я должен уточнить, что ssh-соединение должно быть активным, чтобы у меня был доступ в Интернет. Таким образом, когда я закрываю окно терминала, мне нужно, чтобы ssh-соединение все еще было активным.
Ответы
Ответ 1
У меня был script, который зацикливался на 6 серверах, вызывая через ssh в фоновом режиме. В 1 части script было применено неверное поведение поставщика; приложение не "отпустило" соединение должным образом. (другие части script с использованием ssh в фоновом режиме работали нормально).
Я обнаружил, что использование ssh -t -t устраняет проблему. Может быть, это тоже поможет вам.
(товарищ по команде нашел это в Интернете, и мы потратили так много времени, я никогда не возвращался, чтобы прочитать статью, которая предложила это. На странице руководства в нашей системе не было намека на то, что это возможно)
Надеюсь, что это поможет.
Ответ 2
Вот несколько соображений, которые могут помочь.
Суб-оболочки
Sub-shells развивает новые процессы, но не возвращает управление вызывающей оболочке. Если вы хотите разветкить суб-оболочку для выполнения этой работы, вам нужно добавить &
в строку.
(ssh [email protected]) &
Но это не выглядит убедительной причиной использования под-оболочки. Если у вас были команды с номерами, которые вы хотели выполнить по порядку друг от друга, но параллельно с вызывающей оболочкой, возможно, это было бы полезно. Например...
(dothis.sh; thenthis.sh; andthislastthingtoo.sh) &
Разветвление
Я не уверен, почему &
не работает для вас, но может быть стоит посмотреть nohup
, Это делает команду "иммунной" проверять сигналы.
nohup ssh [email protected]
(попробуйте с и без &
в конце)
Пароли
Не хранить пароли в script необходимо для любой автоматизации ssh. Вы можете выполнить это с использованием криптографии с открытым ключом, которая является неотъемлемой чертой ssh. Я не буду вдаваться в подробности здесь, потому что есть number of отличный ресурсы во всех средах с настройкой этого. Я настоятельно рекомендую исследовать это дальше.
Если вы идете по этому маршруту, я также предлагаю запустить ssh в "пакетном режиме", который отключит запрос пароля и автоматически отключится от сервера, если он перестанет отвечать на запросы через 5 минут.
ssh -o 'BatchMode=yes' [email protected]
Постоянство
Затем, если вы хотите сохранить соединение, запустите некоторый глупый цикл в bash!:)
ssh -o 'BatchMode=yes' [email protected] "while (( 1 == 1 )); do sleep 60; done"
Ответ 3
Вы можете попытаться удвоить фоновый myProg2, чтобы отсоединить его от tty:
# cf. "Wizard Boot Camp, Part Six: Daemons & Subshells",
# http://www.linux-mag.com/id/5981
(myProg2 &) &
Другим вариантом может быть использование инструмента daemon из пакета libslack:
http://ingvar.blog.linpro.no/2009/05/18/todays-sysadmin-tip-using-libslack-daemon-to-daemonize-a-script/
Ответ 4
Наличие ssh с псевдо-tty в фоновой оболочке
В дополнение к ответу @shellter я хотел бы сделать некоторую точность:
где @shelter сказал:
В man-странице нашей системы не было намека на то, что такая возможность возможна
В моей системе (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
like /dev/pts/0
), вы можете запустить их с помощью -t
.
Но это будет работать только в том случае, если ssh
запускается из консоли консоли (ака с собственным pty). Если вы планируете запустить их, это консольный сеанс без консоли, например фоновые сценарии, вы можете использовать Multiple -t для принудительного распределения псевдо-tty из 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'
Это гарантирует, что соединение останется включенным, даже если я не нажимаю клавишу более двух минут.
Ответ 5
Проблема с &
заключается в том, что ssh теряет доступ к своему стандартному вводу (терминалу), поэтому, когда он переходит к чтению чего-либо для отправки на другую сторону, он либо получает ошибку, либо выходит, либо является kill
ed системой с 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
Прошло некоторое время с тех пор, как я использовал ssh, и я не могу проверить его прямо сейчас, но вы попробовали ключ -f?
ssh -f [email protected]
На странице man написано, что это фоны ssh. Не уверен, почему &
не будет работать, но я предполагаю, что он интерпретирует его как команду для запуска на удаленной машине.
Ответ 7
Может быть, экран + ssh тоже будет соответствовать счету?
Что-то вроде:
screen -d -m -S sessionName cmd
screen -d -m -S sessionName cmd &
# reconnect with
screen -r sessionName