bashの中で対話型コマンドを実行する時の課題
シェルの中で対話型コマンドを実行するとき、それも対話内容によって複雑な処理が必要かつ、入力が変わる時、コマンドへの入力方法がわからない。
例えば、letsencrypt のワイルドーカード証明証の発行などがそれ。
letsencrypt のワイルドーカード証明証では、対話型コマンドの中で、自身のDNSにTXTレコードを指定の値で作れって指示があり、それを設定した後にDNSが公開されるまで待って「改行」を入力する必要があります。
簡単な対話型の実現なら expect コマンドでもいいが、上記のような処理では対応が難しい。
で、どう実現するか? コマンドの出力を受け取るのは簡単ですが、難しいのは入力。yesコマンドや echoを pipe で繋ぐと、待って欲しいのに勝手に入力してしまう。 このタイミングをコントロールする方法があります。
実現方法
touch input.txt
status=0
tail -f input.txt | {実行したいコマンド} | while read -r res;
do
if [[ $status == 1 ]]; then
{status1 + 次の入力(res)を使って、実際のコマンド処理} [*1]
echo "" >> input.txt # ⭐️ここがポイント!! これでコマンドに入力できます!
status=2
elif [[ $res == {コマンドの対話出力でフックしたい文字列[*2]}* ]]; then
status=1
fi
done
rm -f input.txt
- letsencrypt のワイルドーカード証明証なら、ここでDNS TXTレコードに指定された値を設定する。DNS公開が安定するまでsleepした方が良いので、 sleep 300 などをコマンド実行後に入れる。
- ここに _acme-challenge.{ドメイン名} を入れれば、次の行で指定値を出力するので、そこでDNS TXTレコードを作るわけです。 それが [*1]のコマンドです。
まとめ
ポイントは、以下の形で、tail -f で入力できるようにし、read でコマンド出力を参照しながら必要に応じて tail -f で監視するファイルにecho入力するところです。
tailf -f 入力ファイル | コマンド | read -r res;
do
echo 入力文字 >> 入力ファイル # ⭐️これでコマンドに入力を渡せるんです。
done
letsencrypt のワイルドカード証明書の更新の場合、上記以外にもフックしなきゃいけない文字列は幾つかあります。すでに証明証発行済みの場合などのためです。