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

Ska*_*arj 59 ssh bash pid background-process

我正在使用程序协同与ssh隧道

它工作,我只需打开一个控制台类型这两个命令:

ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
synergyc localhost
Run Code Online (Sandbox Code Playgroud)

因为我很懒,我制作了一个Bash-Script,只需点击一下图标即可运行:

#!/bin/bash
ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
synergyc localhost
Run Code Online (Sandbox Code Playgroud)

上述与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
Run Code Online (Sandbox Code Playgroud)

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

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

ndi*_*dim 73

快速摘要:不起作用.

我的第一个想法是你需要在后台启动进程来获取它们的PID $!.

一种模式

some_program &
some_pid=$!
wait $some_pid
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我想这是因为人们(像我一样)google如何获取bash中最后启动过程的PID,找到这个页面,跳到第一个答案,然后去"哦,对,$ !,我忘了".然后我们投票并且不知道或关心作者想要什么. (37认同)
  • 正如作者所提到的,它不适用于ssh -f,因为它会产生一个新进程.我不知道,为什么人们继续推动这一点. (9认同)
  • @JoePinsonault我责怪这个问题的标题. (2认同)

gho*_*oti 58

与所有尊重的用户pgrep,pkill,ps | 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
Run Code Online (Sandbox Code Playgroud)

这些导致ssh到背景本身,让隧道打开.但是如果隧道消失了,我就卡住了,如果我想找到它,我必须解析我的进程列表并回家我有"正确"的ssh(如果我不小心推出了多个看起来那么类似).

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

host officefirewall colocatedserver
    ControlMaster auto
    ControlPath ~/.ssh/cm_sockets/%r@%h:%p
Run Code Online (Sandbox Code Playgroud)

上面的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
Run Code Online (Sandbox Code Playgroud)

而在这一点上,隧道(与控制SSH会话)走了,而不需要使用锤子(kill,killall,pkill等).

把它带回你的用例......

你建立希望通过其隧道syngergyc交谈syngergysTCP端口12345.上,我会做一些像下面这样.

~/.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
Run Code Online (Sandbox Code Playgroud)

请注意,命令行-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
Run Code Online (Sandbox Code Playgroud)

-f选项指示隧道,在ControlPath上留下一个套接字以便稍后关闭隧道.如果ssh失败(可能是由于网络错误或者ExitOnForwardFailure),则不需要退出隧道,但如果它没有失败(else),则启动synergyc,然后隧道在退出后关闭.

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

  • 我希望更多人投票赞成这一点. (5认同)
  • @GeorgiosPolitis,谢谢!我不会反对!:-) 唉,我的答案是在问题提出 5 年后才给出的。随着时间的推移,也许会有更多的人对此投赞成票。 (2认同)
  • @ Randall,我不同意.虽然原始问题可以通过仅针对Synergy客户端和服务器的极简主义答案来实现,但我的答案是在OP最后一次登录后差不多5年写的.用例并不重要,因为它对OP没有帮助.像这样的问题通过提供更通用的东西来更好地为社区服务,更广泛的受众可以从中获益. (2认同)

zra*_*hen 21

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

$ pidof init
1
Run Code Online (Sandbox Code Playgroud)

  • man:"Pidof找到了命名程序的进程id(pids)".默认情况下,它将查找所有匹配的进程,但您可以使用"-s"选项仅选择匹配的第一个进程.另一个有用的选项是"-x"(脚本也是如此),它也会查找运行命名脚本的shell的pids.退出代码会告诉您实用程序是否找到了任何内容. (2认同)

小智 16

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

lsof -t -i @localhost:12345 -sTCP:listen
Run Code Online (Sandbox Code Playgroud)

例子:

PID=$(lsof -t -i @localhost:12345 -sTCP:listen)
lsof -t -i @localhost:12345 -sTCP:listen >/dev/null && echo "Port in use"
Run Code Online (Sandbox Code Playgroud)


Ska*_*arj 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
Run Code Online (Sandbox Code Playgroud)

(你可以将grep集成到awk中,但我现在太懒了)


小智 9

您可以删除-f它,使其在后台运行,然后运行它eval并自己强制它到后台.

然后你可以抓住pid.确保把&该内eval声明.

eval "ssh -N -L localhost:12345:otherHost:12345 otherUser@OtherHost & " 
tunnelpid=$!
Run Code Online (Sandbox Code Playgroud)

  • 对不起,你为什么还需要eval呢?不会是$!只需抓住最后一个后台进程?谢谢 (6认同)