SSHを使用してリモートサーバーに接続するときに、スクリプトが内容を確認してstdinに戻る前にプライベートスクリプトを展開するスクリプトを作成しようとしています。これはすべて1つの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'
ただし、これには複数の接続を使用します。 1つの接続だけをどのように使用できますか?
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
同じストリームを介してシェルコード、tarファイル、およびユーザー入力を送信するには、潜在的にパスワードまたはキーパスワードのフレーズが必要ですが、ssh -t
非常ssh
に不器用で脆弱です。
confファイルが大きすぎず、環境変数を受け入れることができ、リモートsshdのAcceptEnv LC_*
構成に1つがある場合(通常の場合)、次のbase64のいずれかにエンコードされたtgzファイルを渡すことができます。
#! /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'
(また、リモートシステム上のユーザーのログインシェルがPOSIXに似ているとします。)
そうでない場合、最も簡単な方法はおそらく複数の呼び出しを使用することssh
ですが、すべて接続多重機能を使用して同じログインセッションを共有することです(ControlMaster
//マニュアルページの指示および/またはこのサイトの例を参照)。ControlPath
ControlPersist
最新バージョンのopensshを使用する別の方法は、-R remote_socket:local_socket
Unixドメインソケットを使用してtarファイルを転送することです(zsh/net/socket
例:zshモジュールを使用)。