我如何杀死后台/分离ssh会话?

我正在使用程序协同与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脚本也起作用,但是现在我也想通过一个鼠标点击杀死协同作用和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 ...组合,必须有一个更简单的方法。)

快速总结:将无法正常工作。

我的第一个想法是,你需要在后台启动进程来得到他们的PID $!

像一个模式

 some_program & some_pid=$! wait $some_pid 

可能会做你所需要的…除了那么ssh将不会在前台要求密码。

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

对于pgreppkillps | awk的用户都应有的尊重 ps | awk等,有一个更好的方法。

考虑一下,如果你依靠ps -aux | grep ... ps -aux | grep ...find一个过程,你冒着碰撞的危险。 您可能有一个用例,那是不太可能的,但作为一般规则,这不是一条路要走。

SSH提供了一个pipe理和控制后台进程的机制。 但是像许多SSH一样,这是一个“先进”的特征,许多人(似乎从这里的其他答案)不知道它的存在。

在我自己的用例中,我有一个工作站在家里,我想离开一个连接到我办公室的内部networking上的HTTP代理的隧道,另一个让我快速访问位于同一地点的服务器上的pipe理接口。 这就是你如何创build从家里发起的基本隧道:

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

这些导致ssh自身背景,使隧道开放。 但是,如果隧道消失,我卡住了,如果我想find它,我必须parsing我的进程列表和家里我有“正确”的SSH(如果我不小心启动了多个看起来类似)。

相反,如果我想要pipe理多个连接,我使用SSH的ControlMasterconfiguration选项以及-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会话)消失了,不需要使用锤子( killkillallpkill等)。

把它带回你的用例…

你正在build立隧道,通过它你想要syngergyc与TCP端口syngergys上的syngergyc交谈。为此,我会做类似下面的事情。

添加一个条目到你的~/.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}行,以确保在build立隧道后您可以进行控制。

然后,你可以修改你的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上留下一个套接字以稍后closures隧道。 如果ssh失败(这可能是由于networking错误或ExitOnForwardFailure ),则不需要退出隧道,但是如果没有失败( else ),synergyc将启动,然后隧道在退出后closures。

您可能还想查看是否可以使用SSH选项LocalCommand在您的sshconfiguration文件中从右启动synergyc

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

 $ pidof init 1 

您可以使用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" 

以及我不想在命令的末尾添加一个&,因为连接将死,如果控制台wintowclosures…所以我结束了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中,但是现在我太懒了)

您可以删除-f ,使其在后台运行,然后使用eval运行,并将其自动强制为背景。

你可以抓住pid 。 确保将&放在eval语句中。

 eval "ssh -N -L localhost:12345:otherHost:12345 otherUser@OtherHost & " tunnelpid=$! 

对于synergyc(以及大多数试图自我保护的程序)来说,这更是一个特例。 使用$! 会起作用,除了synergyc在执行过程中执行一个clone()系统调用,它将给它一个新的PID,而不是bash认为它有的。 如果你想解决这个问题,那么你可以使用$ !,那么你可以告诉synergyc留在forground,然后背景。

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

synergyc还做了一些其他的事情,如autorestart,如果你想pipe理它,你可能想closures。

另一个select是使用pgrep来查找最新的ssh进程的PID

 ssh -fNTL 8073:localhost:873 otherUser@OtherHost tunnelPID=$(pgrep -n -x ssh) synergyc localhost kill -HUP $tunnelPID 

你可以看看绑定到你的本地端口的ssh过程,使用这一行:

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

它使用localhost上的端口12345 / TCP返回进程的PID。 所以你不必过滤ps所有ssh结果。

如果你只需要检查, 如果该端口被绑定,使用:

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

如果没有绑定,则返回1 0如果某人正在侦听此端口,则返回0

基于@ghoti的非常好的回答,这里是一个简单的脚本(用于testing)利用SSH控制套接字,而不需要额外的configuration:

 #!/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只有在隧道build立成功后才会启动,只要synergyc返回,它本身就会closures。 虽然解决scheme缺乏适当的错误报告。