期待してる - `expect` コマンド 再び

今回は shellscript での expcet コマンドのお話.

以前にも,処理中に対話式でパスワード入力とか求められる操作を自動化したいと,この expect コマンドについて触れました,この expect コマンドの spawn にてパイプ pipe | を使う場合は,ちょっとしたコツが必要みたい.

と言うのを知りました.

具体的な事例をもって示しますと,こんな感じです.;

expect -c "
  spawn bash -c \"echo ${path_is} | sudo tee -a /etc/shells\"
  expect \"Password:\"
  send \"${PASSWORD}\n\"
  interact
"

話は spawn のライン.

spawn へ定義するコマンドの記述に,パイプ | を使用する場合,bash -c と《直接 bash を書いて》やる方法を採ると良いらしいです.

SJSA Grade Six -  The Year I RebelledSJSA Grade Six - The Year I Rebelled / Michael 1952



ちなみに,bash-c オプションに続く string,今回の例で言いますと echo ${path_is} | sudo tee -a /etc/shells の部分,この部分を囲むために使うダブルクォーテーション " は,きちんとエスケープ \ を挿しておく必要があります.
エスケープなしに spawn bash -c "echo ${path_is} | sudo tee -a /etc/shells" としてしまいますと,バババババっとエラーを吐いてきます.

つい忘れがち,という事で,これ地味に大事.

expectスクリプトとしての「"」は\でエスケープする.》ってことなのでしょう.
他にもこちら記載のコード見てもそのようです.メモ.

と,さて閑話休題

spawn echo ${path_is} | sudo tee -a /etc/shells と言うの,ダメらしいです

上に示した正解に対して,イケていない方を示すと,こう.;

expect -c "
  spawn echo ${path_is} | sudo tee -a /etc/shells
  expect \"Password:\"
  send \"${PASSWORD}\n\"
  interact
"

自身も,当初,上のような書き方をしてました.

このような書き方をしますと,次のようなエラーを落とします.

send: spawn id exp6 not open while executing

...ちょっと何言ってるかわからない.*1

通常*2ですと,spawn に記述するコマンド文は " で囲むことなく,いわゆる “そのまんま” 定義できるものと思っていて,当然その感覚で書いていたのですが,どうもそうではないケースがあるという事のようです.

では,どう言うことなのかと言うと,こう言うことらしいです.

それは,spawn が,パイプ | の前だけをコマンドだと思ってしまうから

expectの処理中は、パイプを通した処理の標準入出力の仕様が異なるのでしょうか。
: 略
これは、
spawn が、パイプの前だけをコマンドだと思って先に実行してしまうからです。
ですから、何とか spawn に 1コマンドだと思わせれば良いのです。

だそう.

言われれば,そんなことですか,と言った振る舞い.
思いの外,原始的と言いますか単純な話で,何か,拍子抜けと言うよりは,かえってモヤモヤ感が残ると言うのが正直あったりしますが.

上述の引用元にもありますが,bash コマンドを直接書く方法だけではなく,別途,スクリプトファイルを用意する方法もあります.

その他に,別途スクリプトファイルを用意することで

このファイルには,本来 spawn にて指定するはずの処理の部分を記載することになります.

そして用意したそのファイルを,spawn 側にて指定する,と言うやり方です.

今回の話で具体的に言いますと.
イメージとして分かり易いと思うので上手く動作しない方のコードを例にしますが,spawn echo ${path_is} | sudo tee -a /etc/shells の “echo ${path_is} | sudo tee -a /etc/shells” の部分を,別途,スクリプトファイルへ切り離す,といった考え方です.*3

上述引用元もありますが,ここにも同じ話がありましたので挙げておきたいと思います.;

If you can’t setup keys, you can put the “tar … | ssh …” line into another script and call it with spawn, just pass the required parameter

.i.e:

sh spawn anotherscript.bash $sdir $port $login $host

「"tar … | ssh …“ の部分を他のスクリプトに置いて,spawn にてそいつ呼びゃ良いんじゃない?」なこと言ってますね.

ついでに,自分の場合は,可能ならファイルを増やたくなかったので,この別ファイルに設ける方法は採りませんでした.

そんなこんなで、まさか Yahooクッソ袋ゥ(伊集院光トーンにて)知恵袋にお世話になろう時が来るとは思ってもおりませんでした.*4

はいおしまい。

*1:それでも腹キメて ‘expect’ のドキュメントに触れてみたりしたのですが,さあぁっっっぱり.
“spawn id” やら “exp6” とかっての辺りが話上,トークンらしく扱われている雰囲気を感じるまでは順応できたものの.つか,し,正直,ダルイなって :-P

*2:と申しますか,それは「参照してきたコード見るとそうだったので」というレベルでの無知が故の,個人的な閉じた世界での “通常” なのではありますが

*3:勿論,その部分をただ持っていくというのではなく,そのファイル自身,正常に実行できるように書き換えなりは,必要.

*4:何か,ちょっと汚されたようで以下伏