以下のように、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
は関数に問題がないように見えますが、スクリプト文字列内では値がないようです...したがって、cd $2
はcd
と評価され、ls $logfilepattern
はls
と評価されます。
これは簡略化されたバージョンであり、さらに重要なことに、引用符が修正されています(変数を二重引用符で囲み、必要に応じて非変数テキストを一重引用符で囲みます)
#!/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
_と_$logfilepattern
_が含まれています(一重引用符で囲まれたテキストは文字通りssh
コマンドの引数として渡されるため、反対側で実行するコードスニペットです) 。これらは、削除側で実行されているシェルの変数を参照します。
実際には、リモート側で2つのシェルを実行していますが、あまり役に立ちません。 SSHは常にシェルを呼び出します。複数の引数を渡すことができますが、それらは間にスペースを入れて結合されています。リモート側のシェルが実行されます
_bash -c \ #script string starts here
cd $2
…
_
最初の行は、_-c
_と単一のスペースの2つの引数を使用してbash
を呼び出します。これにより、シェルが呼び出されて何も実行されません。リモートコマンドの残りの部分は、SSHによって呼び出されたシェルで実行されます。
あなたがやろうとしていることをする簡単な方法は
_ssh "$1" "cd $2 && ls -l $logfilepattern"
_
ノート:
ls
の出力の解析は無意味です :_for file in `ls *`
_は、ls
の出力の解析が中断することを除いて、_for file in *
_の複雑な記述方法です。ファイル名に特殊文字が含まれている場合。$2
_と_$logfilepattern
_はどちらも、リモート側で実行されるスクリプトの一部として解析されます。 $(touch foo)
のようなものが含まれている場合、そのコードが実行されます。この特定のユースケースでは、それは必ずしも問題ではありませんが、注意する必要があるものです。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"
_