ec2インスタンスにpexpectでアクセスしてコマンドを実行する[Python]
ec2インスタンスにpexpectでアクセスしてコマンドを実行する方法を説明します.
abstract
# ライブラリのインポート なければ pip install pexpect
import pexpect
# ec2にssh
child = pexpect.spawn('ssh -i ~/.ssh/user.pem ec2-user@xxx.xxx.xxx.xxx')
# プロンプトが現れるのを待つ ここが正しくないとその後の処理もうまく行われない
child.expect("\[ec2-user@ip-xxx-xxx-xxx-xxx ~]\$")
# コマンドの準備
ls = 'ls -l'
# コマンド実行
child.sendline(ls)
# コマンド実行後のプロンプトが現るのを待つ
child.expect("\[ec2-user@ip-xxx-xxx-xxx-xxx ~]\$")
# 一つ前のexpectから一行上のexpectまでの出力を取得,バイナリ形式のため文字列に変換
res = child.before
print(res.decode('utf-8'))
# 終了
child.close()
EC2インスタンスの作成
pexpectの実験のために作成するインスタンスなので最小限で作成しています.お好みの設定にして作成してください.
- 無料利用枠のAmazon Linux 64ビット(x86)を選択
- 無料利用枠のt2.microを選択
- セキュリティグループの編集で,sshのソースにマイIPを指定
- 作成したインスタンスの概要に書いてあるパブリックIPv4アドレスをコピーしておく
EC2インスタンスにssh
AWSのEC2にmacからSSHする方法の記事を参考にインスタンスにsshができることを確かめてください.
macからのsshからしか試していないため,他のOSの人は各自で調べてください.
pexpectの準備
Python3系がすでにインストールされていることを想定しています.
pexpectをpipでインストールします.
$pip install pexpect
pexpectでコマンドを実行
以下のサンプルプログラムはssh先のインスタンスでtouchコマンドでファイルを作成して,ls -lコマンドでその結果を取得しています.(ipアドレスはマスクしているため,適宜自分の環境に合わせてください)
child.sendline()でコマンドを実行し,child.expect()で一区切り,child.beforeで出力結果を取得するという流れです
ハマりどころは以下です.
- 実行結果が空文字の場合は,expectがうまく設定できていない
- expectに指定する文字列で正規表現がつかえない
- いくつかのサイトでは expect(".*") のように指定していましたが,そのような指定ではうまく行かなかったため,プロンプトの文字列をそのまま書いています.
- [ はエスケープが必要なので \[ にする
- 文字列がバイナリで帰ってくるので,strにdecodeする
import pexpect
child = pexpect.spawn('ssh -i ~/.ssh/user.pem ec2-user@xxx.xxx.xxx.xxx')
child.expect("\[ec2-user@ip-xxx-xxx-xxx-xxx ~]\$")
touch = 'touch test.txt'
child.sendline(touch)
child.expect("\[ec2-user@ip-xxx-xxx-xxx-xxx ~]\$")
res = child.before
print(res.decode('utf-8'))
ls = 'ls -l'
child.sendline(ls)
child.expect("\[ec2-user@ip-xxx-xxx-xxx-xxx ~]\$")
res = child.before
print(res.decode('utf-8'))
child.close()
以下がその実行結果です.
$python3 test.py
touch test.txt
^[kec2-user@ip-xxx-xxx-xxx-xxx:~^[\
ls -l
合計 0
-rw-rw-r-- 1 ec2-user ec2-user 0 7月 12 13:45 test.txt
^[kec2-user@ip-xxx-xxx-xxx-xxx:~^[\
この記事が気に入ったらサポートをしてみませんか?