bash 如何终止后台/分离的 ssh 会话?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1821968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:44:33  来源:igfitidea点击:

How do I kill a backgrounded/detached ssh session?

bashsshbackground-processpid

提问by Skaarj

I am using the program synergy together with an ssh tunnel

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

It works, i just have to open an console an type these two commands:

它有效,我只需要打开一个控制台并输入这两个命令:

ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
synergyc localhost

because im lazy i made an Bash-Script which is run with one mouseclick on an icon:

因为我很懒,所以我制作了一个 Bash 脚本,只需在图标上单击一下鼠标即可运行:

#!/bin/bash
ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
synergyc localhost

the Bash-Script above works as well, but now i also want to kill synergy and the ssh tunnel via one mouseclick, so i have to save the PIDs of synergy and ssh into file to kill them later:

上面的 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

But the files of this script are empty.

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

How do I get the PIDs of ssh and synergy?
(I try to avoid ps aux | grep ... | awk ... | sed ...combinations, there has to be an easier way.)

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

采纳答案by Skaarj

well i dont want to add an & at the end of the commands as the connection will die if the console wintow is closed ... so i ended up with an ps-grep-awk-sed-combo

好吧,我不想在命令的末尾添加 & ,因为如果控制台 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  }'` > /tmp/synergyPIDs/ssh
synergyc localhost
echo `ps aux | grep -F 'synergyc localhost' | grep -v -F 'grep' | awk '{ print  }'` > /tmp/synergyPIDs/synergy

(you could integrate grep into awk, but im too lazy now)

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

回答by ndim

Quick summary: Will not work.

快速总结:不起作用。

My first idea is that you need to start the processes in the background to get their PIDs with $!.

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

A pattern like

一个模式像

some_program &
some_pid=$!
wait $some_pid

might do what you need... except that then ssh won't be in the foreground to ask for passphrases any more.

可能会做你需要做的事......除了然后 ssh 不会在前台要求密码短语了。

Well then, you might need something different after all. ssh -fprobably spawns a new process your shell can never know from invoking it anyway. Ideally, ssh itself would offer a way to write its PID into some file.

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

回答by ghoti

With all due respect to the users of pgrep, pkill, ps | awk, etc, there is a muchbetter way.

与所有尊重的用户pgreppkillps | awk等,还有很多更好的办法。

Consider that if you rely on ps -aux | grep ...to find a process you run the risk of a collision. You may have a use case where that is unlikely, but as a general rule, it's not the way to go.

考虑一下,如果您依赖于ps -aux | grep ...找到一个进程,您将面临发生冲突的风险。您可能有一个不太可能的用例,但作为一般规则,这不是可行的方法。

SSH provides a mechanism for managing and controlling background processes. But like so many SSH things, it's an "advanced" feature, and many people (it seems, from the other answers here) are unaware of its existence.

SSH 提供了一种管理和控制后台进程的机制。但是就像许多 SSH 东西一样,它是一个“高级”功能,很多人(似乎,从这里的其他答案来看)并不知道它的存在。

In my own use case, I have a workstation at home on which I want to leave a tunnel that connects to an HTTP proxy on the internal network at my office, and another one that gives me quick access to management interfaces on co-located servers. This is how you might create the basic tunnels, initiated from home:

在我自己的用例中,我在家里有一个工作站,我想在该工作站上留下一个隧道,该隧道连接到我办公室内部网络上的 HTTP 代理,另一个让我可以快速访问位于同一地点的服务器上的管理界面. 这是您创建基本隧道的方式,从家里启动:

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

These cause ssh to background itself, leaving the tunnels open. But if the tunnel goes away, I'm stuck, and if I want to find it, I have to parse my process list and home I've got the "right" ssh (in case I've accidentally launched multiple ones that look similar).

这些会导致 ssh 自己后台运行,从而使隧道保持打开状态。但是如果隧道消失了,我就被卡住了,如果我想找到它,我必须解析我的进程列表,然后我得到了“正确的”ssh(以防我不小心启动了多个看起来像相似的)。

Instead, if I want to manage multiple connections, I use SSH's ControlMasterconfig option, along with the -Ocommand-line option for control. For example, with the following in my ~/.ssh/configfile,

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

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

the ssh commands above, when run, will leave spoor in ~/.ssh/cm_sockets/which can then provide access for control, for example:

上面的 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/[email protected]:22): No such file or directory

And at this point, the tunnel (and controlling SSH session) is gone, without the need to use a hammer (kill, killall, pkill, etc).

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

Bringing this back to your use-case...

将此带回您的用例...

You're establishing the tunnel through which you want syngergycto talk to syngergyson TCP port 12345. For that, I'd do something like the following.

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

Add an entry to your ~/.ssh/configfile:

在您的~/.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

Note that the command line -Loption is handled with the LocalForwardkeyword, and the Control{Master,Path} lines are included to make sure you have control after the tunnel is established.

请注意,命令行-L选项是使用LocalForward关键字处理的,并且包含 Control{Master,Path} 行以确保您在隧道建立后拥有控制权。

Then, you might modify your bash script to something like this:

然后,您可以将 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

The -foption backgrounds the tunnel, leaving a socket on your ControlPath to close the tunnel later. If the ssh fails (which it might due to a network error or ExitOnForwardFailure), there's no need to exit the tunnel, but if it did not fail (else), synergyc is launched and then the tunnel is closed after it exits.

-f选项使隧道成为后台,在 ControlPath 上留下一个套接字以稍后关闭隧道。如果 ssh 失败(可能是由于网络错误或ExitOnForwardFailure),则无需退出隧道,但如果没有失败 ( else),则启动 Synergyc,然后在退出后关闭隧道。

You might also want to look in to whether the SSH option LocalCommandcould be used to launch synergycfrom right within your ssh config file.

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

回答by zrathen

just came across this thread and wanted to mention the "pidof" linux utility:

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

$ pidof init
1

回答by Atle

You can use lsof to show the pid of the process listening to port 12345 on localhost:

您可以使用 lsof 来显示在本地主机上侦听端口 12345 的进程的 pid:

lsof -t -i @localhost:12345 -sTCP:listen

Examples:

例子:

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

回答by l0k3y3

You can drop the -f, which makes it run it in background, then run it with evaland force it to the background yourself.

您可以删除-f,这使其在后台运行,然后运行它eval并自己强制将其置于后台。

You can then grab the pid. Make sure to put the &within the evalstatement.

然后您可以抓取pid. 确保把&该内eval声明。

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

回答by deltaray

This is more of a special case for synergyc (and most other programs that try to daemonize themselves). Using $! would work, except that synergyc does a clone() syscall during execution that will give it a new PID other than the one that bash thought it has. If you want to get around this so that you can use $!, then you can tell synergyc to stay in the forground and then background it.

这更像是synergyc(以及大多数其他试图自我保护的程序)的特例。使用 $! 会起作用,除了synergyc 在执行期间执行clone() 系统调用,这会给它一个新的PID,而不是bash 认为它拥有的PID。如果你想解决这个问题以便你可以使用 $!,那么你可以告诉 Synergyc 留在前台,然后将它作为后台。

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

synergyc also does a few other things like autorestart that you may want to turn off if you are trying to manage it.

Synergyc 还执行其他一些操作,例如 autorestart,如果您尝试对其进行管理,您可能希望将其关闭。

回答by Lenny

Another option is to use pgrep to find the PID of the newest ssh process

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

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

回答by foo

You could look out for the ssh proceess that is bound to your local port, using this line:

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

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

It returns the PID of the process using port 12345/TCP on localhost. So you don't have to filter all sshresults from ps.

它使用本地主机上的端口 12345/TCP 返回进程的 PID。因此,您不必过滤ssh来自ps.

If you just need to check, ifthat port is bound, use:

如果你只需要检查,如果该端口绑定,使用:

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

Returns 1if none bound or 0if someone is listening to this port.

返回1如果没有约束或者0如果有人听了这个端口。

回答by doak

Based on the very good answer of @ghoti, here is a simpler script (for testing) utilising the SSH control socketswithout the need of extra configuration:

基于@goti 的非常好的答案,这里有一个更简单的脚本(用于测试),无需额外配置即可使用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

synergycwill be only started if tunnel has been established successfully, which itself will be closed as soon as synergycreturns. Albeit the solution lacks proper error reporting.

synergyc只有在隧道成功建立后才会启动,隧道本身将在synergyc返回后立即关闭。尽管解决方案缺乏正确的错误报告。