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

时间:2009-11-30 19:44:21

标签: bash ssh background-process pid

我正在使用程序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也可以,但是现在我也想通过一次鼠标点击杀死synergy和ssh隧道,所以我必须将synergy和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和协同作用的PID?
(我尽量避免ps aux | grep ... | awk ... | sed ...组合,必须有一种更简单的方法。)

11 个答案:

答案 0 :(得分:72)

快速摘要:无效。

我的第一个想法是你需要在后台启动进程以获得$!的PID。

这样的模式
some_program &
some_pid=$!
wait $some_pid

可能会做你需要的......除了那个ssh不会在前台再问一下passphrases。

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

答案 1 :(得分:56)

pgreppkillps | awk等用户充满敬意,有一个 更好方式。

考虑一下,如果您依靠ps -aux | grep ...来查找流程,则会面临发生冲突的风险。您可能有一个不太可能的用例,但作为一般规则,它不是可行的方法。

SSH提供了一种管理和控制后台进程的机制。但是像许多SSH一样,它是一个先进的"功能,很多人(似乎从这里的其他答案)不知道它的存在。

在我自己的用例中,我在家里有一个工作站,我希望在我的办公室留下一个连接到内部网络上的HTTP代理的隧道,另一个允许我快速访问co上的管理界面的工作站。 - 定位服务器。这就是你如何创建从家里发起的基本隧道:

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

这些导致ssh到背景本身,使隧道保持打开状态。但如果隧道消失了,我就会陷入困境,如果我想找到它,我必须解析我的流程列表并回家我已经得到了#34;正确的" ssh(如果我意外地发起了多个看似相似的东西)。

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

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

上面的ssh命令在运行时会在~/.ssh/cm_sockets/中留下spoor,然后可以提供对控件的访问,例如:

$ 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等。

将此内容反馈给您的用例......

您正在建立隧道,您希望syngergyc通过TCP端口12345与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然后隧道在退出后关闭。

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

答案 2 :(得分:21)

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

$ pidof init
1

答案 3 :(得分: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"

答案 4 :(得分:12)

好吧,我不想添加&在命令结束时,如果控制台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中,但我现在太懒了)

答案 5 :(得分:9)

您可以删除-f,这会让它在后台运行,然后使用eval运行它并自行强制它到后台。

然后你可以抓住pid。请务必将&放在eval声明中。

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

答案 6 :(得分:4)

对于synergyc(以及大多数其他尝试自我控制的程序)而言,这是一个特例。用$!可以工作,除了synergyc在执行期间执行一个clone()系统调用,它将为它提供一个新的PID,而不是bash认为的那个。如果你想绕过这个以便你可以使用$ !,那么你可以告诉synergyc留在forground然后背景它。

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

synergyc还会执行一些其他操作,比如自动启动,如果您尝试管理它,可能需要关闭。

答案 7 :(得分:3)

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

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

答案 8 :(得分:2)

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

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

它使用localhost上的端口12345 / TCP返回进程的PID。因此,您无需过滤ssh的所有ps结果。

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

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

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

答案 9 :(得分:0)

基于@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返回,隧道本身就会关闭。 虽然解决方案缺乏适当的错误报告。

答案 10 :(得分:0)

这里有很多有趣的答案,但是没有人提到SSH 确实的手册页描述了这种情况! (请参见TCP FORWARDING部分)。他们提供的解决方案更加简单:

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

详细信息:

  1. 首先,我们通过隧道启动SSH;多亏了-f,它才会启动连接,然后才分叉到后台(与ssh ... &; pid=$!的解决方案不同,其中ssh发送到后台,并且在隧道创建之前之前执行了下一条命令) )。在远程计算机上,它将运行sleep 10,它将等待10秒钟,然后结束。
  2. 在10秒钟之内,我们应该启动所需的命令,在这种情况下为synergyc localhost。它将连接到隧道,然后SSH将知道该隧道正在使用中。
  3. 经过10秒钟后,sleep 10命令将完成。但是synergyc仍在使用该隧道,因此SSH 在隧道释放之前(即,synergyc关闭套接字之前)不会关闭连接连接
  4. 关闭synergyc时,它将释放隧道,而SSH将依次终止自身并关闭连接。

此方法的唯一缺点是,如果我们使用的程序由于某种原因而关闭并重新打开连接,则SSH将在连接关闭后立即关闭隧道,并且该程序将无法重新连接。如果存在问题,则应使用@doak's answer中所述的方法,该方法使用控制套接字正确终止SSH连接,并使用-f确保在SSH派生到后台时创建隧道。