Linux シェルスクリプト: expect で外部コマンドの出力を待機する

expect コマンドを使用すると、任意のコマンドの出力を待ち受けて、自動でそれに応答するといったことを実現できます。

expect の基本的な使い方

Linux のコマンド expect がインストールされていない場合は、パッケージ管理ツール(aptyum)を使用してインストールしてください(macOS には最初からインストールされています)。 まずは、簡単な例として、下記のような簡単なユーザ入力を必要とするスクリプトを自動で動作させてみます。

greet.sh
#!/bin/bash

echo -n "Enter your name: "
read name
echo "Hello, $name"

これをそのまま実行すると、下記のようにユーザ入力の待ち受け状態となります。

$ ./greet.sh
Enter your name:

このような状態になったときに、自動的に入力を行うには、下記のように expect -c コマンドを使ったシェルスクリプトを作成します。

sample.sh
#!/bin/bash

expect -c "
  set timeout 3
  spawn ./greet.sh
  expect \"Enter your name:\"
  send \"Maku\n\"
  interact
"

expect -c の後ろのダブルクォートで囲まれた部分には、expect で実行するスクリプトを記述します。 この中でダブルクォートを使用したいときは、\" のようにエスケープしなければいけないことに注意してください。 スクリプト中の各行は次のような意味を持っています。

  • set timeout 3外部プログラムの実行を 3 秒待つ
  • spawn ./greet.sh指定した外部プログラム (./greet.sh) を実行する
  • expect "Enter your name:"外部プログラムの出力 (Enter your name:) を待つ
  • send "Makun"外部プログラムに Maku と入力して、最後に Enter を入力する
  • interact外部プログラムとのインタラクションへ戻る

上記のシェルスクリプトを実行すると、外部プログラム greet.sh の入力待ちに対して、自動的に Maku という入力を行います。

実行結果
$ ./sample.sh
spawn ./greet.sh
Enter your name: Maku
Hello, Maku

コマンドラインからのパスワード入力を自動化する

あまりよくない例かもしれませんが、sshrsync コマンドなどのパスワード入力も同様に自動化することができます。 下記のスクリプトを実行すると、ssh コマンドがパスワード入力を求めてきたときに、自動でパスワードを入力してログイン処理が完了します。

例: ssh 接続時のパスワード入力を自動化 (autologin.sh)
#!/bin/bash

expect -c "
  set timeout 3
  spawn ssh username@example.com
  expect \"password:\"
  send \"x5sd6sfc\n\"
  interact
"
実行結果
$ ./autologin.sh
spawn ssh username@example.com
username@examle.com's password:
Last login: Sat Nov 10 19:58:51 2018 from hogehoge.ap.example.jp

username$

ログイン後に、何らかのコマンド(例えば ls -aFl)を実行するところまで自動化したいのであれば、下記のようにプロンプトの $ を待ち受けて次の入力を行えばよいでしょう。

#!/bin/bash

expect -c "
  set timeout 3
  spawn ssh username@example.com
  expect \"password:\"
  send \"x5sd6sfc\n\"

  expect \"$\"
  send \"ls -aFl\n\"

  interact
"

ちなみに、rsync コマンドでファイル転送するときも同様にパスワード入力を自動化できます。

#!/bin/bash

expect -c "
  spawn rsync -r -h -v --delete public user@example.com:public
  expect \"Password:\"
  send \"abcabcabc\n\"
  interact
"

ただし、このような使い方をすると、シェルスクリプトにパスワードをそのまま記述することになるので、ファイルの保存場所には十分に注意してください。 ここでは、プログラムの例としてパスワード入力を扱いましたが、SSH 接続を行うのであれば、通常は ~/.ssh/config ファイルによる SSH キー設定 を用いた方がよいでしょう。