Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 如何终止后台/分离的ssh会话?_Bash_Ssh_Background Process_Pid - Fatal编程技术网

Bash 如何终止后台/分离的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

我将程序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
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