ローカルサーバー(場所1)からリモートサーバー(場所2)に変数を渡そうとします。このコードの目的は、リモートサーバーの事前定義された場所からファイルをコピーすることです。簡単に言えば、事前定義されたパスを使用してlocation2からlocation1にファイルをコピーしたいと思います。ここで、location1 はローカルサーバーにあり、location2 はリモートサーバーです。コードスニペットを見てください。
$location1=somewhere/on/local_server
$location2=somewhere/on/remote_server
sshpass -p "password" \
ssh [email protected] 'su -lc "cp -r $location2 $location1";'
私が得るエラーは、$location1と$location2の両方が定義されていないことです。また、場所のパスはいつでも変更される可能性があり、コードの変更が手動で行われると痛みを伴う可能性があるため、手動で入力したくありません。
答え1
シェル変数はまさにシェル変数です。クライアントシェルのこの変数は、このssh
コマンドまたはリモートホストから起動されたシェルとしてアクセスできません。sshd
出口シェル変数は、実行されたコマンドに環境変数として渡されます。したがって、エクスポートするとlocation1
環境変数としてに渡されます。設定ディレクティブ(またはまたは...経由)をssh
使用すると、リモートホストに転送しようとします。SendEnv
ssh
-o
~/.ssh/config
/etc/ssh/ssh_config
ssh
sshd
ただし、これを機能させるには、この変数を受け取るための設定ディレクティブsshd
が必要ですAcceptEnv
。しかし、セキュリティ上の理由から、通常はそうではありません。
ただし、多くのデフォルトのssh / sshd展開では、LC_
名前が(ローカライズのために)で始まる変数渡しを許可します。したがって、次の利点を享受できます。
LC_location1=$location1 LC_location2=$location2 ssh host
'su -lc '\''cp -r -- "$LC_location2" "$LC_location1"'\''
あるいは、ローカルシェル拡張変数をリモートシェルのコマンドラインに渡すこともできます。
ssh host "su -lc 'cp -r -- $location2 $location1'"
ただし、これは以下を実行するのと同じです。
eval eval "cp -r -- $location2 $location1"
つまり、これらの変数は引数として渡されず、シェル(リモートユーザーのログインシェルで始まる)コードcp
として解釈されます(2回)。したがって、変数がある場合、劇的な結果が発生します。sh
su
$location1
/somewhere;rm -rf /
正しい方法は、リモートシェルを正しくエスケープすることです。シェルには2つのレベルがあるため、単一引用符を2回エスケープする必要があります(ksh93
ここでは//構文が使用されています)。bash
zsh
escaped_location1=\'${location1//\'/\'\\\'\'}\'
escaped_location1=${escaped_location1//\'/\'\\\'\'}
escaped_location2=\'${location2//\'/\'\\\'\'}\'
escaped_location2=${escaped_location2//\'/\'\\\'\'}
ssh host "su -lc 'cp -r -- $escaped_location2 $escaped_location1'"
リモートユーザーのログインシェルはBourneに似ていると仮定します。
答え2
変数は一重引用符の間では拡張されません。
二重引用符を使用し、内部二重引用符をエスケープします。
sshpass -p "password" \
ssh [email protected] "su -lc \"cp -r $location2 $location1\";"
または、一重引用符を閉じてもう一度開きます。
sshpass -p "password" \
ssh [email protected] 'su -lc "cp -r '$location2' '$location1'";'
bash は自動的に文字列連結を実行します。
注:テストされていません。$locationX
スペースやその他の奇妙な文字が含まれていると混乱する可能性があります。
答え3
Lesmanaの答えに加えて、2番目の例では変数を引用する必要があります。
sshpass -p "password" \
ssh [email protected] 'su -lc "cp -r '\\\"$location2\\\"' '\\\"$location1\\\"'";'
答え4
サービスを更新するために私が書いたこのスクリプトをチェックしてください。
PROJ=$2
リモートランタイム環境に渡されます。
function update-env () {
env=$1
proj=$2
# script for update test env
ssh -A root@$2.$1.test.com PROJ=$2 'bash -s' <<'ENDSSH'
# commands to run on remote host
su gmuser
cd /srv/apps/$PROJ
/usr/bin/git pull
exit
supervisorctl restart $PROJ
ENDSSH
}