Bash 如何终止后台/分离的ssh会话?
我将程序synergy与ssh隧道一起使用 它可以工作,我只需要打开一个控制台,键入以下两个命令:Bash 如何终止后台/分离的ssh会话?,bash,ssh,background-process,pid,Bash,Ssh,Background Process,Pid,我将程序synergy与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 syn
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脚本也可以工作,但现在我还想通过一个鼠标点击来杀死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和synergy的PID?(我尽量避免使用ps aux | grep…| awk…| sed…组合,必须有一种更简单的方法。)快速总结:不起作用。 我的第一个想法是,您需要在后台启动进程,以便使用
$获得它们的PID代码>
像这样的图案
some_program &
some_pid=$!
wait $some_pid
可能会做你需要的。。。除了ssh不再在前台请求密码之外
那么,你可能需要一些不同的东西ssh-f
可能会产生一个新的进程,您的shell无论如何调用它都无法知道。理想情况下,ssh本身将提供一种将其PID写入某个文件的方法。我不想在命令末尾添加一个&因为如果控制台wintow关闭,连接将终止。。。所以我最终得到了一个ps-grep-awk-sed组合
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中,但我现在太懒了)您可以使用以下行查找绑定到本地端口的ssh进程:
netstat -tpln | grep 127\.0\.0\.1:12345 | awk '{print $7}' | sed 's#/.*##'
它使用本地主机上的端口12345/TCP返回进程的PID。因此,您不必过滤来自ps
的所有ssh
结果
如果您只需要检查,如果该端口已绑定,请使用:
netstat -tln | grep 127\.0\.0\.1:12345 >/dev/null 2>&1
如果未绑定,则返回1
;如果有人正在收听此端口,则返回0
。您可以删除-f
,使其在后台运行,然后使用eval
运行,并强制将其置于后台
然后,您可以抓取pid
。确保将和放在eval
语句中
eval "ssh -N -L localhost:12345:otherHost:12345 otherUser@OtherHost & "
tunnelpid=$!
刚刚遇到这个问题,想提及“pidof”linux实用程序:
$ pidof init
1
另一个选项是使用pgrep查找最新ssh进程的PID
ssh -fNTL 8073:localhost:873 otherUser@OtherHost
tunnelPID=$(pgrep -n -x ssh)
synergyc localhost
kill -HUP $tunnelPID
这对于synergyc(以及大多数其他试图将自己后台化的程序)来说更是一个特例。使用$!除了synergyc在执行过程中执行clone()系统调用,这将为它提供一个新的PID,而不是bash认为的PID。如果您想避开此问题,以便可以使用$!,然后,您可以告诉synergyc留在前面的回合中,然后对其进行背景处理
synergyc -f -n mydesktop remoteip &
synergypid=$!
synergyc还执行一些其他操作,如自动重新启动,如果您试图管理它,您可能希望将其关闭。您可以使用lsof显示侦听本地主机上端口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"
对于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
这会导致ssh自身进入后台,使通道打开。但是如果隧道消失了,我就卡住了,如果我想找到它,我必须解析我的进程列表,并且我已经得到了“正确的”ssh(以防我意外地启动了多个看起来类似的)
相反,如果我想管理多个连接,我将使用SSH的ControlMaster
config选项以及用于控制的-O
命令行选项。例如,在我的~/.ssh/config
文件中
host officefirewall colocatedserver
ControlMaster auto
ControlPath ~/.ssh/cm_sockets/%r@%h:%p
上面的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
此时,隧道(和控制SSH会话)消失了,不需要使用锤子(kill
,killall
,pkill
,等等)
将其带回您的用例…
您正在建立一个通道,希望通过该通道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
关键字处理的,并且包含了控制{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
选项设置隧道背景,在控制路径上留下一个套接字,以便稍后关闭隧道。如果ssh失败(可能是由于网络错误或exitonfrowardfailure
),则无需退出隧道,但如果它没有失败(else
),synergyc将启动,然后隧道在退出后关闭
您可能还想查看SSH选项LocalCommand
是否可用于从SSH配置文件的右侧启动synergyc
。基于@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
ssh -fL 12345:localhost:12345 user@remoteserver sleep 10
synergyc localhost