我正在尝试创建一个脚本,当您使用 SSH 连接到远程服务器时,该脚本会检查内容并部署您的个人脚本,然后再返回标准输入,所有这些都在一个 SSH 连接中进行(否则您必须多次进行身份验证。 ..)。
我有一个有效的脚本。
#!/bin/zsh
HOST="$1"
# Install ZSH if it's not already installed
ssh "$HOST" <<- EOF
if [ ! -x /bin/zsh ]; then
if [ -x "/usr/bin/dnf" ]; then
sudo dnf install -y zsh >/dev/null
elif [ -x "/usr/bin/apt-get" ]; then
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y zsh >/dev/null
fi
fi
EOF
# Copy ZSH configuration to remote host
tar -cz -f - -C "$HOME" --exclude="*.zwc" {.zshrc,.zshenv,.config/zsh/{p10k.zsh,plugins}} | ssh "$HOST" 'tar -xz -f - -C "$HOME"'
# Login with ZSH in a login shell
ssh -t "$HOST" 'SHELL=/bin/zsh /bin/zsh -l'
但它为此使用多个连接。我怎样才能只使用一个连接?
我尝试过 POC
#!/bin/zsh
HOST="$1"
# redirect 3 to standard output
exec 3>&1
ssh -t $HOST >&3 <&1 &
# doesn't work, doesnt execute on remote host
echo "hostname"
# this as well
echo "hostname" >&1
# works, give back the tty of the remote server to the user
exec 1<&0
wait
echo "THE END"
但在返回 tty 之前我无法在远程服务器上执行命令。而且我也不知道如何发送文件。
有办法做到这一切吗?
答案1
通过同一流发送 shell 代码、tar 文件和用户输入ssh -t
,同时又ssh
可能要求输入密码或关键密码短语,这将是极其笨拙和脆弱的。
如果您的conf文件不是太大并且可以适应环境变量,并且远程sshdAcceptEnv LC_*
在其配置中有一个(这是常见的),您可以传递以其中之一编码的tgz文件base64:
#! /bin/zsh -
HOST=${1?}
LC_ZC=$(
tar -cz -f - -C ~ --exclude="*.zwc" {.zshrc,.zshenv,.config/zsh/{p10k.zsh,plugins}} |
base64
) exec ssh -o SendEnv=LC_ZC -t "$HOST" '
if ! command -v zsh; then
if command -v dnf; then
sudo dnf install -y zsh
elif command -v apt-get; then
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y zsh
fi
fi > /dev/null
echo "$LC_ZC" | base64 -d | tar -zxf - -C ~
unset -v LC_ZC
SHELL=/bin/zsh exec /bin/zsh -l'
(还假设远程计算机上用户的登录 shell 是类似 POSIX 的)。
如果没有,最简单的方法可能是使用多个调用,ssh
但所有调用都与连接多路复用功能共享相同的登录会话(请参阅手册页中的ControlMaster
//说明和/或查看此站点上的示例)。ControlPath
ControlPersist
使用最新版本的 openssh 的另一种方法是-R remote_socket:local_socket
使用 Unix 域套接字来传输 tar 文件(zsh/net/socket
例如使用 zsh 的模块)。