我如何杀死后台/分离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写入某个文件的方法。
对于pgrep
, pkill
, ps | 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的ControlMaster
configuration选项以及-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
等)。
把它带回你的用例…
你正在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缺乏适当的错误报告。