ローカルサーバーからリモートサーバーに変数を渡すには?

ローカルサーバーからリモートサーバーに変数を渡すには?

ローカルサーバー(場所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_configsshsshd

ただし、これを機能させるには、この変数を受け取るための設定ディレクティブ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回)。したがって、変数がある場合、劇的な結果が発生します。shsu$location1/somewhere;rm -rf /

正しい方法は、リモートシェルを正しくエスケープすることです。シェルには2つのレベルがあるため、単一引用符を2回エスケープする必要があります(ksh93ここでは//構文が使用されています)。bashzsh

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
}

関連情報