用于设置临时 SSH 隧道的 Bash 脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2241063/
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:55:54  来源:igfitidea点击:

Bash script to set up a temporary SSH tunnel

bashssh

提问by jm.

On Cygwin, I want a Bash script to:

在 Cygwin 上,我想要一个 Bash 脚本来:

  1. Create an SSH tunnel to a remote server.
  2. Do some work locally that uses the tunnel.
  3. Then shut down the tunnel.
  1. 创建到远程服务器的 SSH 隧道。
  2. 在本地做一些使用隧道的工作。
  3. 然后关闭隧道。

The shutdown part has me perplexed.

关机部分让我很困惑。

Currently, I have a lame solution. In one shell I run the following to create a tunnel:

目前,我有一个蹩脚的解决方案。在一个 shell 中,我运行以下命令来创建一个隧道:

# Create the tunnel - this works! It runs forever, until the shell is quit.
ssh -nNT -L 50000:localhost:3306 [email protected]

Then, in another shell window, I do my work:

然后,在另一个 shell 窗口中,我做我的工作:

# Do some MySQL stuff over local port 50000 (which goes to remote port 3306)

Finally, when I am done, I close the first shell window to kill the tunnel.

最后,当我完成后,我关闭第一个 shell 窗口以终止隧道。

I'd like to do this all in one script like:

我想在一个脚本中完成这一切,例如:

# Create tunnel
# Do work
# Kill tunnel

How do I keep track of the tunnel process, so I know which one to kill?

如何跟踪隧道进程,以便知道要杀死哪个进程?

回答by Chris McCormick

You can do this cleanly with an ssh 'control socket'. To talk to an already-running SSH process and get it's pid, kill it etc. Use the 'control socket' (-M for master and -S for socket) as follows:

您可以使用 ssh '控制套接字' 干净利落地做到这一点。要与已经在运行的 SSH 进程对话并获取它的 pid,杀死它等等。使用“控制套接字”(-M 代表 master,-S 代表套接字),如下所示:

$ ssh -M -S my-ctrl-socket -fnNT -L 50000:localhost:3306 [email protected]
$ ssh -S my-ctrl-socket -O check [email protected]
Master running (pid=3517) 
$ ssh -S my-ctrl-socket -O exit [email protected]
Exit request sent. 

Note that my-ctrl-socket will be an actual file that is created.

请注意, my-ctrl-socket 将是创建的实际文件。

I got this info from a very RTFM reply on the OpenSSH mailing list.

我从OpenSSH 邮件列表上的一个非常 RTFM 的回复中得到了这个信息。

回答by Maine Guy

You can tell SSH to background itself with the -f option but you won't get the PID with $!. Also instead of having your script sleep an arbitrary amount of time before you use the tunnel, you can use -o ExitOnForwardFailure=yes with -f and SSH will wait for all remote port forwards to be successfully established before placing itself in the background. You can grep the output of ps to get the PID. For example you can use

您可以使用 -f 选项告诉 SSH 自己进行后台处理,但您不会使用 $! 获得 PID。此外,不要让脚本在使用隧道之前休眠任意时间,您可以使用 -o ExitOnForwardFailure=yes 和 -f,SSH 将等待所有远程端口转发成功建立,然后再将自己置于后台。您可以 grep ps 的输出来获取 PID。例如,您可以使用

...
ssh -Cfo ExitOnForwardFailure=yes -NL 9999:localhost:5900 $REMOTE_HOST
PID=$(pgrep -f 'NL 9999:')
[ "$PID" ] || exit 1
...

and be pretty sure you're getting the desired PID

并且很确定你得到了想要的 PID

回答by ZeissS

  • You can tell sshto go into background with &and not create a shell on the other side (just open the tunnel) with a command line flag (I see you already did this with -N).
  • Save the PID with PID=$!
  • Do your stuff
  • kill $PID
  • 您可以使用命令行标志告诉ssh进入后台,&而不是在另一侧创建外壳(只需打开隧道)(我看到您已经使用了-N)。
  • 使用以下命令保存 PID PID=$!
  • 做你的事
  • kill $PID

EDIT: Fixed $? to $! and added the &

编辑:固定 $? 到 $! 并添加了 &

回答by too much php

I prefer to launch a new shell for separate tasks and I often use the following command combination:

我更喜欢为单独的任务启动一个新的 shell,我经常使用以下命令组合:

  $ sudo bash; exit

or sometimes:

或有时:

  $ : > sensitive-temporary-data.txt; bash; rm -f sensitive-temporary-data.txt; exit

These commands create a nested shell where I can do all my work; when I'm finished I hit CTRL-D and the parent shell cleans up and exits as well. You could easily throw bash;into your ssh tunnel script just before the killpart so that when you log out of the nested shell your tunnel will be closed:

这些命令创建了一个嵌套的 shell,我可以在其中完成所有工作;当我完成时,我按下 CTRL-D,父 shell 也会清理并退出。您可以轻松地bash;在该kill部分之前加入您的 ssh 隧道脚本,以便当您退出嵌套 shell 时,您的隧道将被关闭:

#!/bin/bash
ssh -nNT ... &
PID=$!
bash
kill $PID

回答by Phil Pelanne

Another potential option -- if you can install the expect package, you should be able to script the whole thing. Some good examples here: http://en.wikipedia.org/wiki/Expect

另一个可能的选择——如果你可以安装 expect 包,你应该能够编写整个程序的脚本。这里有一些很好的例子:http: //en.wikipedia.org/wiki/Expect

回答by Valentin Rocher

You could launch the sshwith a &a the end, to put it in the background and grab its id when doing. Then you just have to do a killof that id when you're done.

你可以ssh用一个&结尾来启动它,把它放在后台并在做的时候获取它的 id。然后你只需要在完成后做一个kill那个 id 。