SSHを介してパスワードで保護された複数のコンピュータを再起動するbashスクリプトを作成しようとしています。 .txtファイルにすべてのIPリストがあり、スクリプトがそこからIPを読み取るようにします。私のMacにはsshpassがないので、Expectコマンドを使っていたずらしました。 sshpassなしで行う方法はありますか?
これまで私はこれを持っています:
#!/bin/bash
for server in 'testreboot.txt'; do
expect -c 'spawn ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5
administrator@$server "sudo shutdown -r now"; expect "Password:"; send
"password\r"; interact'
done
testreboot.txtには、テストマシンのIPアドレスのみが一覧表示されます。可能ですか、それとも変数に割り当てる必要がありますか?実行しようとすると、さまざまなエラーが発生し続けます。
答え1
文字列を一重引用符で囲み、シェルが挿入されるのを防ぎます$server
。コード作成方法(TCL)もこの形式を使用して変数を挿入しますが、expect
TCLコードでは$server
この形式を使用しません。set server ...
したがって、シェルがそれを挿入せず、TCLがそれを設定しないため、エラーが発生します。 1つの方法は、TCL式を二重引用符で囲み、シェルがシェル$server
変数に挿入できるようにすることです。
$ server=example; expect -c 'puts $server'
can't read "server": no such variable
while executing
"puts $server"
$ server=example; expect -c "puts $server"
example
$
ただし、これは"
シェルの補間を妨げないように、TCLコード内のすべての項目をエスケープする必要があることを意味します。これは、特にコマンドが長く複雑になるにつれて急速に醜くなり、デバッグが困難になる可能性があります。
$ server=example; expect -c "puts \"a server named '$server'\""
a server named 'example'
$
別のオプションは、パラメータをTCL変数として読み取ることです。しかし残念ながら、-c
フラグコードはexpect
パラメータリストにアクセスできません。これは、パラメータリストがTCLで利用可能になる前にchar *argv[]
コードが実行されるためです。-c
したがって、これをTCL変数として使用するには、$server
スクリプトをTCLとして再構築する必要があります。
#!/usr/bin/env expect
set fh [open testreboot.txt r]
while {[gets $fh server] >= 0} {
spawn -noecho ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 \
administrator@$server
expect -ex "Password:"
send "Hunter2\r"
expect -ex {$ }
send "sudo shutdown -r now\r"
expect -ex "Password:"
send "Hunter2\r"
interact
}
これには、改善されたエラー処理、タイムアウト、より良いシェルプロンプトマッチングなどが必要になる場合があります。