65

我将程序协同与 ssh 隧道一起使用

它工作,我只需要打开一个控制台输入这两个命令:

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

因为我很懒,所以我制作了一个 Bash 脚本,只需在图标上单击鼠标即可运行:

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

上面的 Bash-Script 也可以,但现在我还想通过单击鼠标来终止协同和 ssh 隧道,因此我必须将协同和 ssh 的 PID 保存到文件中以便以后终止它们:

#!/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

但是这个脚本的文件是空的。

如何获得 ssh 和 synergy 的 PID?
(我尽量避免ps aux | grep ... | awk ... | sed ...组合,必须有更简单的方法。)

4

11 回答 11

74

快速总结:不会工作。

我的第一个想法是您需要在后台启动进程以使用$!.

像这样的图案

some_program &
some_pid=$!
wait $some_pid

可能会做您需要的事情...除了 ssh 将不再在前台询问密码。

那么,你可能需要一些不同的东西。ssh -f可能会产生一个新进程,你的 shell 无论如何都无法通过调用它来知道它。理想情况下,ssh 本身会提供一种将其 PID 写入某个文件的方法。

于 2009-11-30T19:57:33.587 回答
74

在充分尊重 , , 等的用户的情况下pgreppkillps | 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 自己后台运行,从而使隧道保持打开状态。但是如果隧道消失了,我就卡住了,如果我想找到它,我必须解析我的进程列表和 home 我有“正确”的 ssh(以防我不小心启动了多个看起来相似的)。

相反,如果我想管理多个连接,我会使用 SSH 的ControlMaster配置选项以及-O用于控制的命令行选项。例如,在我的~/.ssh/config文件中有以下内容,

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

上面的 ssh 命令在运行时将离开 spoor,~/.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 会话)消失了,无需使用锤子(killkillallpkill等)。

将其带回您的用例...

您正在建立要在 TCP 端口 12345 上与之通信的隧道。syngergyc为此syngergys,我将执行以下操作。

~/.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 并在退出后关闭隧道。

您可能还想查看是否LocalCommand可以使用SSH 选项synergyc从您的 ssh 配置文件中直接启动。

于 2014-10-20T16:28:02.403 回答
21

刚刚遇到这个线程,想提一下“pidof”linux实用程序:

$ pidof init
1
于 2012-07-04T12:46:17.133 回答
16

您可以使用 lsof 显示在 localhost 上侦听端口 12345 的进程的 pid:

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"
于 2013-04-11T06:35:06.157 回答
13

好吧,我不想在命令末尾添加一个 &,因为如果控制台 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 中,但我现在太懒了)

于 2009-12-01T13:56:15.340 回答
9

您可以删除-f,使其在后台运行,然后自行运行eval并强制其进入后台。

然后,您可以抓住pid. 确保将 放在&语句eval中。

eval "ssh -N -L localhost:12345:otherHost:12345 otherUser@OtherHost & " 
tunnelpid=$!
于 2012-05-30T13:16:08.203 回答
4

这更像是 synergyc(以及大多数其他试图自我守护的程序)的特殊情况。使用 $! 会起作用,除了 synergyc 在执行期间会执行一个 clone() 系统调用,这将给它一个新的 PID,而不是 bash 认为它拥有的那个。如果您想解决这个问题以便可以使用 $!,那么您可以告诉 synergyc 留在前台,然后将其置于后台。

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

synergyc 还做了一些其他的事情,比如自动重启,如果你想管理它,你可能想关闭它。

于 2012-12-10T21:59:56.880 回答
3

另一种选择是使用 pgrep 查找最新 ssh 进程的 PID

ssh -fNTL 8073:localhost:873 otherUser@OtherHost
tunnelPID=$(pgrep -n -x ssh)
synergyc localhost
kill -HUP $tunnelPID
于 2012-08-24T21:55:05.843 回答
3

基于@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返回后立即关闭。尽管该解决方案缺乏适当的错误报告。

于 2016-06-29T11:08:08.533 回答
2

您可以使用以下行查找绑定到本地端口的 ssh 进程:

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

它使用本地主机上的端口 12345/TCP 返回进程的 PID。因此,您不必sshps.

如果您只需要检查该端口是否已绑定,请使用

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

1如果没有绑定或0有人正在监听此端口,则返回。

于 2012-03-03T22:46:44.707 回答
2

这里有很多有趣的答案,但没有人提到 SSH 的手册页确实描述了这种确切的情况!(见TCP FORWARDING章节)。他们提供的解决方案要简单得多:

ssh -fL 12345:localhost:12345 user@remoteserver sleep 10
synergyc localhost

现在详细说明:

  1. 首先我们用隧道启动 SSH;由于-f它将启动连接,然后才分叉到后台(与将 ssh 发送到后台并在创建隧道之前ssh ... &; pid=$!执行下一个命令的解决方案不同)。在远程机器上它将运行,等待 10 秒然后结束。sleep 10
  2. 在 10 秒内,我们应该启动我们想要的命令,在这种情况下是synergyc localhost. 它将连接到隧道,然后 SSH 将知道隧道正在使用中。
  3. 10 秒后,sleep 10命令将完成。但隧道仍在使用中synergyc,所以 SSH不会关闭底层连接,直到隧道被释放(即直到synergyc关闭套接字)。
  4. 关闭时synergyc,它会释放隧道,而 SSH 反过来会自行终止,关闭连接。

这种方法的唯一缺点是,如果我们使用的程序由于某种原因关闭并重新打开连接,那么 SSH 将在连接关闭后立即关闭隧道,并且程序将无法重新连接。如果这是一个问题,那么您应该使用@doak 的答案中描述的方法,该方法使用控制套接字正确终止 SSH 连接并用于-f确保在 SSH 分叉到后台时创建隧道。

于 2020-05-02T00:13:27.263 回答