次のように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
リモートコンピュータでスクリプトを実行しています。スクリプトには$2
andが含まれています$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
ます。ssh
cd
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_DIRECTORY
cd
変数の内容のコマンドを呼び出すには、リモート側で実行されているスクリプトでそれを二重引用符で囲みます。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"