在Shell脚本中设置并使用SSH ControlMaster会话

在Shell脚本中设置并使用SSH ControlMaster会话,shell,ssh,Shell,Ssh,我正在编写一个脚本,其中包含在远程服务器上运行所需的多组命令,并在其间处理结果。目前,这是通过为每一组命令运行ssh来实现的,但是这需要每次建立一个新的连接并进行身份验证,这很慢 我最近读到了SSH中的ControlMaster选项,这似乎正是我所需要的,即通过单个SSH连接运行单独SSH会话的能力 然而,我非常不清楚的是,我将如何在shell脚本中实现这一点。例如,我想这样构造它: #!/bin/sh HOST="$1" # Make sure we clean up after ourse

我正在编写一个脚本,其中包含在远程服务器上运行所需的多组命令,并在其间处理结果。目前,这是通过为每一组命令运行
ssh
来实现的,但是这需要每次建立一个新的连接并进行身份验证,这很慢

我最近读到了SSH中的
ControlMaster
选项,这似乎正是我所需要的,即通过单个SSH连接运行单独SSH会话的能力

然而,我非常不清楚的是,我将如何在shell脚本中实现这一点。例如,我想这样构造它:

#!/bin/sh
HOST="$1"

# Make sure we clean up after ourselves
on_complete() {
    kill $ssh_control_master_id
    rm -r "$tmp_dir"
}
trap 'on_complete 2> /dev/null' SIGINT SIGHUP SIGTERM EXIT

tmp_dir=$(mktemp -d "/tmp/$(basename "$0").XXXXXX")
ssh_control_socket="$tmp_dir/ssh_control_socket"

# Setup control master
ssh -o 'ControlMaster=yes' -S "$ssh_control_socket" "$HOST" &
ssh_control_master_id=$!

# Run initial commands
data=$(ssh -S "$ssh_control_socket" "$HOST" 'echo "Foo"')

# Process the data
echo "$data"

# Run some more commands
data=$(ssh -S "$ssh_control_socket" "$HOST" 'echo "Bar"')

# Process the second batch of data
echo "$data"
这只是一个简单的示例,让您了解一下,但这似乎不是正确的方法,因为运行它会导致第二个
ssh
命令挂起,或者每个命令都会正常运行(创建它们自己的连接)。我也不知道如何等待主连接建立,也就是说,我可能正在运行我的实际命令,而远程连接仍在建立


另一个相关的注意事项是,一旦控制主机运行,关闭它和/或删除它的套接字的正确方法是什么?

您的代码看起来很好。我还没有测试它,但是尝试使用主连接的第一个进程可能会阻塞,直到主连接实际成功建立。您可以使用
-N
选项来避免在主连接上运行假外壳:

ssh -N -o 'ControlMaster=yes' -S "$ssh_control_socket" "$HOST" &

在所有下级会话完成后,简单地终止
ssh
进程是非常好的。

感谢关于
-N
标志的提示,我以前没有注意到这一点!但是,我不清楚在主连接建立之前如何阻止,在
ssh
中是否有这样做的功能?我的假设是,如果您使用
-S
启动
ssh
以请求特定套接字,并且该套接字存在,但主连接尚未完全建立,
ssh
将一直阻止,直到建立连接,而不是打开自己的另一个套接字。如果您使用
-f
而不是符号作为ssh ControlMaster的后台,那么它也将与基于密码的身份验证兼容。否则,它将返回后台,提示输入密码,然后超时。@billyw建议使用
-f
而不是符号。
ssh-f
命令将一直阻塞,直到建立连接为止,因此您将不会像使用ampersand一样出现任何竞争条件。您可以使用
-O check
确保主连接仍处于活动状态,并使用
-O exit
在完成后终止主连接。