我如何杀死后台/分离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的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会话)消失了,不需要使用锤子( 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缺乏适当的错误报告。