Как убить фоновую / отдельную сессию ssh? - PullRequest
58 голосов
/ 30 ноября 2009

Я использую программу Synergy вместе с туннелем SSH

Это работает, мне просто нужно открыть консоль типа этих двух команд:

ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
synergyc localhost

потому что я ленивый, я создал Bash-Script, который запускается одним щелчком мыши на значке:

#!/bin/bash
ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
synergyc localhost

Bash-Script выше работает, но теперь я также хочу убить синергию и ssh-туннель одним щелчком мыши, поэтому мне нужно сохранить PID синергии и ssh в файл, чтобы убить их позже:

#!/bin/bash

mkdir -p /tmp/synergyPIDs || exit 1
rm -f /tmp/synergyPIDs/ssh || exit 1
rm -f /tmp/synergyPIDs/synergy || exit 1

[ ! -e /tmp/synergyPIDs/ssh ] || exit 1
[ ! -e /tmp/synergyPIDs/synergy ] || exit 1

ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
echo $! > /tmp/synergyPIDs/ssh
synergyc localhost
echo $! > /tmp/synergyPIDs/synergy

Но файлы этого скрипта пусты.

Как мне получить PID ssh и синергии?
(Я стараюсь избегать комбинаций ps aux | grep ... | awk ... | sed ..., должен быть более простой способ.)

Ответы [ 10 ]

72 голосов
/ 30 ноября 2009

Краткое резюме: не будет работать.

Моя первая идея заключается в том, что вам нужно запустить процессы в фоновом режиме, чтобы получить их PID с $!.

шаблон как

some_program &
some_pid=$!
wait $some_pid

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

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

56 голосов
/ 20 октября 2014

При всем уважении к пользователям pgrep, pkill, ps | awk и т. Д., Существует намного лучший способ.

Учтите, что если вы используете ps -aux | grep ... для поиска процесса, вы рискуете столкнуться. У вас может быть случай использования, когда это маловероятно, но, как правило, это не тот путь.

SSH предоставляет механизм для управления и контроля фоновых процессов. Но, как и многие другие вещи SSH, это «продвинутая» функция, и многие люди (кажется, из других ответов здесь) не знают о ее существовании.

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

$ ssh -fNT -L8888:proxyhost:8888 -R22222:localhost:22 officefirewall
$ ssh -fNT -L4431:www1:443 -L4432:www2:443 colocatedserver

Это приводит к тому, что ssh отходит на задний план, оставляя туннели открытыми. Но если туннель пропадает, я застреваю, и если я хочу его найти, мне нужно проанализировать мой список процессов, и у меня есть «правильный» ssh (на случай, если я случайно запустил несколько таких, которые выглядят подобный).

Вместо этого, если я хочу управлять несколькими подключениями, я использую опцию конфигурации ControlMaster SSH вместе с опцией командной строки -O для управления. Например, со следующим в моем файле ~/.ssh/config,

host officefirewall colocatedserver
    ControlMaster auto
    ControlPath ~/.ssh/cm_sockets/%r@%h:%p

Команды ssh, приведенные выше, при запуске оставят спор в ~/.ssh/cm_sockets/, который затем может предоставить доступ для управления, например:

$ ssh -O check officefirewall
Master running (pid=23980)
$ ssh -O exit officefirewall
Exit request sent.
$ ssh -O check officefirewall
Control socket connect(/home/ghoti/.ssh/cm_socket/ghoti@192.0.2.5:22): No such file or directory

И на этом этапе туннель (и управляющий сеанс SSH) пропал без необходимости использования молотка (kill, killall, pkill и т. Д.).

Возвращение к вашему сценарию использования ...

Вы устанавливаете туннель, через который вы хотите, чтобы syngergyc говорил с syngergys через TCP-порт 12345. Для этого я бы сделал что-то вроде следующего.

Добавить запись в ваш ~/.ssh/config файл:

Host otherHosttunnel
    HostName otherHost
    User otherUser
    LocalForward 12345 otherHost:12345
    RequestTTY no
    ExitOnForwardFailure yes
    ControlMaster auto
    ControlPath ~/.ssh/cm_sockets/%r@%h:%p

Обратите внимание, что параметр командной строки -L обрабатывается с помощью ключевого слова LocalForward, а строки Control {Master, Path} включены, чтобы обеспечить контроль после создания туннеля.

Затем вы можете изменить свой bash-скрипт на что-то вроде этого:

#!/bin/bash

if ! ssh -f -N otherHosttunnel; then
    echo "ERROR: couldn't start tunnel." >&2
    exit 1
else
    synergyc localhost
    ssh -O exit otherHosttunnel
fi

Опция -f скрывает туннель, оставляя сокет на ControlPath, чтобы позже закрыть туннель. Если происходит сбой ssh ​​(что может произойти из-за сетевой ошибки или ExitOnForwardFailure), нет необходимости выходить из туннеля, но если он не вышел из строя (else), запускается synergyc, а затем туннель закрывается после него. выходы.

Возможно, вы захотите узнать, можно ли использовать опцию SSH LocalCommand для запуска synergyc прямо из вашего файла конфигурации ssh.

21 голосов
/ 04 июля 2012

только что наткнулся на эту тему и хотел упомянуть утилиту linux "pidof":

$ pidof init
1
16 голосов
/ 11 апреля 2013

Вы можете использовать lsof для отображения pid процесса, прослушивающего порт 12345 на локальном хосте:

lsof -t -i @localhost:12345 -sTCP:listen

Примеры:

PID=$(lsof -t -i @localhost:12345 -sTCP:listen)
lsof -t -i @localhost:12345 -sTCP:listen >/dev/null && echo "Port in use"
12 голосов
/ 01 декабря 2009

ну, я не хочу добавлять & в конце команд, так как соединение прекратит работу, если консоль wintow закрыта ... поэтому я получил ps-grep-awk-sed-combo

ssh -f -N -L localhost:12345:otherHost:12345   otherUser@otherHost
echo `ps aux | grep -F 'ssh -f -N -L localhost' | grep -v -F 'grep' | awk '{ print $2 }'` > /tmp/synergyPIDs/ssh
synergyc localhost
echo `ps aux | grep -F 'synergyc localhost' | grep -v -F 'grep' | awk '{ print $2 }'` > /tmp/synergyPIDs/synergy

(вы могли бы интегрировать grep в awk, но теперь мне лень)

9 голосов
/ 30 мая 2012

Вы можете сбросить -f, что заставляет его запускать его в фоновом режиме, а затем запустить его с eval и самостоятельно перевести его на фон.

Затем вы можете получить pid. Обязательно поместите & в оператор eval.

eval "ssh -N -L localhost:12345:otherHost:12345 otherUser@OtherHost & " 
tunnelpid=$!
4 голосов
/ 11 декабря 2012

Это скорее особый случай для синергии (и большинства других программ, которые пытаются демонизировать себя). Используя $! будет работать, за исключением того, что synergyc выполняет системный вызов clone () во время выполнения, который даст ему новый PID, отличный от того, который, по мнению bash, имеет. Если вы хотите обойти это, чтобы использовать $ !, тогда вы можете сказать synergyc остаться на переднем плане, а затем фоном.

synergyc -f -n mydesktop remoteip &
synergypid=$!

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

3 голосов
/ 25 августа 2012

Другой вариант - использовать pgrep, чтобы найти PID новейшего процесса ssh

ssh -fNTL 8073:localhost:873 otherUser@OtherHost
tunnelPID=$(pgrep -n -x ssh)
synergyc localhost
kill -HUP $tunnelPID
2 голосов
/ 04 марта 2012

Вы можете посмотреть процесс ssh, связанный с вашим локальным портом, используя эту строку:

netstat -tpln | grep 127\.0\.0\.1:12345 | awk '{print $7}' | sed 's#/.*##'

Возвращает PID процесса, используя порт 12345 / TCP на localhost. Таким образом, вам не нужно фильтровать все ssh результаты из ps.

Если вам просто нужно проверить, , если этот порт связан, используйте:

netstat -tln | grep 127\.0\.0\.1:12345 >/dev/null 2>&1

Возвращает 1, если ничто не связано, или 0, если кто-то слушает этот порт.

0 голосов
/ 29 июня 2016

Основанный на очень хорошем ответе @ghoti, вот более простой сценарий (для тестирования), использующий управляющие сокеты SSH без необходимости дополнительной настройки:

#!/bin/bash
if ssh -fN -MS /tmp/mysocket -L localhost:12345:otherHost:12345 otherUser@otherHost; then
    synergyc localhost
    ssh -S /tmp/mysocket -O exit otherHost
fi

synergyc будет запущен только в том случае, если туннель был успешно установлен, который сам будет закрыт, как только вернется synergyc. Хотя в решении отсутствуют правильные сообщения об ошибках.

...