bashスクリプト関数内でsshにスクリプト文字列を渡す - 変数評価の問題

bashスクリプト関数内でsshにスクリプト文字列を渡す - 変数評価の問題

次のようにSSHを介してリモートスクリプトを実行するbashスクリプトを作成しようとしています。

#!/bin/bash
logfilepattern="*drupal*.gz php*.gz error*.gz"
function getlogcounts {
    echo "in getlogcounts"
    echo  $1
    echo  $2

    ssh $1 bash -c '  \  #script string starts here
    cd $2
    for file in `ls $logfilepattern`
    do
     ls -l $file
    done
'
}

getlogcounts [email protected] "/var/log/mylogs"

$1そして$2関数内ではokが見つかるようですが、スクリプト文字列内では値がないようです。したがって、cd $2評価cdしてls $logfilepattern評価しますls

答え1

これは単純化されたバージョンであり、さらに重要なのは引用が修正されたことです(変数の周りには二重引用符、必要に応じて変数ではなくテキストの周りには一重引用符)。

#!/bin/bash
logfilepattern='*drupal*.gz php*.gz error*.gz'

function getlogcounts {
    echo in getlogcounts
    echo "$1"
    echo "$2"

    ssh "$1" "cd $2 ; ls -l $logfilepattern"
}

getlogcounts [email protected] /var/log/mylogs

答え2

リモートコンピュータでスクリプトを実行しています。スクリプトには$2andが含まれています$logfilepattern(一重引用符の間のテキストは文字通りコマンドの引数として渡されるため、ssh反対側で実行されるコードの一部です)。これは、削除側で実行されるシェルの変数を参照します。

実際、リモート側で2つのシェルを実行していますが、それほど良い結果は得られません。 SSH は常にシェルを呼び出します。複数の引数を渡すことができますが、空白で連結するだけです。リモート側でシェルを実行する

bash -c   \  #script string starts here
cd $2

最初の行は2つの引数とスペースbashで呼び出されます。-cこれは何もしないシェルを呼び出します。リモートコマンドの残りの部分は、SSHによって呼び出されたシェルで実行されます。

欲しいものを行う簡単な方法は次のとおりです。

ssh "$1" "cd $2 && ls -l $logfilepattern"

メモ:

  • 解析された出力lsは意味がありません。for file in `ls *`作成するのは複雑ですが、ファイル名に特殊文字が含まれていると、for file in *解析された出力は中断されます。ls
  • $2どちら$logfilepatternもリモート側で実行されるスクリプトの一部として解析されます。同様の内容が含まれている場合、$(touch foo)コードセグメントが実行されます。この特定のユースケースでは、これが必ずしも問題になるわけではありませんが、知っておくべきことです。
  • &&afterを使用すると、コマンドが失敗した場合に失敗状態がすぐに返されcdます。sshcd

SSHを介して変更されていないコンテンツをリモートシェルに配信する場合は、配信するすべてのコンテンツがリモート側で拡張されるため、コマンドラインのみを使用することは問題になります。しばしば機能する1つの方法は、(クライアントとサーバーのSSH構成によっては必ずしもそうではありません)名前LC_で始まる変数を使用することです。これは、ロケールに関する情報と見なされ、送信されることがよくあります。

LC_DIRECTORY=$2 LC_LOGFILEPATTERN=$logfilepattern ssh "$1" 'cd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN'

引用を参照してください。

  • リモートコンピュータで実行されるコマンドはですcd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN。このリテラルテキストをsshコマンドの引数として渡すには、単一引用符を使用します。
  • $LC_DIRECTORYcd変数の内容のコマンドを呼び出すには、リモート側で実行されているスクリプトでそれを二重引用符で囲みます。
  • LC_LOGFILEPATTERNスペースで区切られたワイルドカードパターンのリストなので、二重引用符ではありません。これは、引用符のない変数拡張が処理される方法です。

変数を転送できない場合は、値に特殊文字を含む変数を保護するために引用符レイヤーを追加する必要があります。

q_directory=$(printf %sa "$2" | sed s/\'/\'\\\'\'/g)
q_directory="'${directory%a}'"
q_logfilepattern=$(printf %sa "$logfilepattern" | sed s/\'/\'\\\'\'/g)
q_logfilepattern="'${q_logfilepattern%a}'"
ssh "$1" "logfilepattern=$q_logfilepattern; cd $q_logfilepattern && ls \$logfilepattern"

関連情報