expectの中でawkを使う方法

以下のコマンドはサーバ($host)をLBから外して、jettyを再起動したあと、再度LBに組み込むものである。変数$hostをfor loopに組み込んで全サーバのjetty再起動を以下のコマンドで自動実行したかった。

処理の流れは各コマンドに記載のコメントの通りだが、expectコマンド内でawkを使う点がうまく書けなかった。

expect -c cmdとexpectコマンドを実行したとき、ターミナル上で実行されるので、shellとしてのエスケープ等を考える必要がある。つまり、cmd部分では[]`のエスケープが必要になる。また変数展開に独特のルールがある。$paramとしたときはshell内で定義された変数として扱われ、\$paramとしたときはexpect内で定義された変数として扱われる。

print $4の箇所をエスケープしなければ、shell内で定義された変数として展開されるが、変数4は定義されていないので、リモートサーバ先で実行したときに以下のように空白になってしまう。

$Nをエスケープすると、expect内で定義された変数とされるので、\$Nとしても定義されていない変数としてエラーが発生する。

can't read "4"ということからexpectコマンドでは4という変数が存在しないと言われてしまっている。

expect -c cmdで実行するほかにもexpectスクリプトファイルを作成して実行する方法がある。expectスクリプトファイルはshellと独立しているので、[]`のエスケープは不要になる。同様に、コマンドの場合にあったエスケープによる変数展開のルールはなく、$paramでexpectスクリプトのsetにより定義された変数を参照する。\$paramとエスケープした場合は、expectスクリプト内に置いて変数ではなく文字列$paramとして解釈される。

今回のawkの例では$4を変数として解釈したくないため、\$4とすれば、正しく動く。

パスワードとリモートホスト名はスクリプト(check_netstat.exp)の引数として渡すことにして、以下のように呼び出す。

netstatの確認部分だけ別スクリプトにするのは微妙なので、他のexpect部分も同様に別スクリプトにして呼び出すようにするのがいい。
書き捨てのコマンドとして実行したく、別スクリプトのようなファイルを作りたくなければ、ヒアドキュメントと/dev/stdinを利用して、次のようにも書ける。expect -c cmdexpect -f fileのいい所取り(書き捨てしやすい + エスケープ周りが扱いやすい)なので、意外と使いやすい。

-Linux
-, ,