`expect` で絞めていただこ - shellscript の実行途中で求められるパスワード入力を自動で

と言うお話.

設定用 shellscript を走らせていて,途中,度々求められるメールやパスワードの入力がどうにかならないものか,と思うようになってきました.

このために結局マシンの前を離れられない.

何のためにスクリプト用意して作業を自動化しているのか,

煩雑な作業を shellscript に任せて自動化してやっほい,という企みもこれではほっとんど意味がないじゃない.

...と彷徨い,ほどなくして expect というコマンドがあることを知ります.

そんなとき、毎回パスワードを入力するのは面倒!(略)という問題を解決するのがexpectというコマンドです。


コマンドの返答を識別して次の入力を自動的に行うコマンド

今回これを使ってみたので,備忘録.

% sw_vers
ProductName:    Mac OS X
ProductVersion: 10.12.2
BuildVersion:   16C67
Expect SF
Expect SF / @markheybo

こんな処理があった場合

shellscript の中に,このような記述があるとします.

path="/usr/local/bin/zsh"
chsh -s ${path}

ログインシェルを変更しようとしているわけですが,ここに来ると確認のパスワードを求めて,処理は止まり待機状態になります.

こんな感じで.

<user> の部分は,各自実際のアカウント名が入ります.;

/usr/local/bin/zsh
Changing shell for <user>.
Password for <user>:

Password for <user>: にカーソルがあるので,ここにパスワードを入れる必要があります.

これを exepect 使ってやると.

こうなります

password="oooooooooo"    # お好きなパスワード等を定義.

expect -c "
  spawn chsh -s "/usr/local/bin/zsh"
  expect \"Password for $(id -u -n):\"
  send \"${password}\n\"
  interact
  "

こうすれば expect 内でパスワードを渡してくれるので,席を離れて安心してコーヒーを淹れに行くことができるようになります.

意識低いメモ

必要最低限は

expect は他にも色々できることがあるようですが,自身のケースにおいては上述の要素で十分かと考えてます.

かなり乱暴で稚拙ではありますが,自分の言葉で.;

  • spawn
    入力(対話)を求めてくるコマンドの処理を,そのまま記載.
  • expect
    こちらの入力を待つ時に出力される文字列を,そのまま記載.
  • send
    入力させたい文字列.パスワード等.
  • intract
    画面に内容を出力.

spawn を処理する時に聞いてくる expect に対し,自動で send を入力してもらう.」

そんなイメージ.

さらに詳細な説明については,既に優れたサイトやエントリ等があるので,そちらを参照頂くとして.

ちなみにインストール using homebrew

brew install expect

有り難い.*1

expect は homebrew の dupes の中なので,導入していない場合は,インストール前に tap をば.

シバンは #!/bin/bash,shellscript なので -c オプションで "" クォートの中に書く

何変なこと言ってるの思われるかもしれませんが.

スクリプトexpect のみならば,#!/usr/bin/expect として使用することができるのだそう

Expect は、 cmdfile を読み込み、実行するコマンドのリストを得る。 Expect は、#! 表記をサポートする OS で、先頭行に

      #!/usr/local/bin/expect -f

と書いておいて実行させることもできる。

ここで言う,"いつものように" shellscript で使う時は,-c オプションを付け,処理内容全体を " で囲んで使うるのだそう.

expect -c は、「これからexpectの処理を開始しますよー」という宣言をしています。

\" ダブルクォート は,エスケープ必要

spawn 以外.

時にエスケープなしでダブルクォート使って記述している情報もあって,どうもスッキリしない感があったのですが,実際に動かして,やはり必要ってことで.

このコード見て,見た目に惚れたのですが,どうも駄目な様子.

ちなみに,このエスケープ必須は shellscript だからと言うことらしいです.#!/usr/bin/expect で書く場合はこういったエスケープ不要っぽい?

結構,普段通りに書けるっぽい

先述の例で変数やコマンド置換 command substitution 使ったりしていますけど,結構普通に記述できるみたいで.

ちなみに,$(id -u -n) はユーザー名を取ってきています.
ここで教えてもらいました.

と言うことで.

今回の作業によって,対話的な処理のために,画面の前でジリジリと待っていなければならない,とか逆に,席離れて戻ってきたら入力待ちで止まっていた,とか,そんなムダな時間を極力減らすことができるようになるんじゃないでしょうか.

はいおしまい.

*1:幾つかオプションをつけているのありましたが,何もなくても特に問題なく.つか,わかっていないだけかもしれませんが笑