次の対話型スクリプトを検討してください。
#!/usr/bin/env bash
set -eu
while true; do
read -p '> '
if [ "$REPLY" == quit ]; then
break
fi
echo "'$REPLY'"
done
expect
今私はそれと対話したいと思います:
#!/usr/bin/env bash
set -eu
echo '
spawn ./1.sh
expect >
send cmd1\n
expect {\n> }
send quit\n
' | expect -d
しかし、実行すると、次のように表示されます。
...
expect: does " cmd1\r\n'cmd1'\r\n> " (spawn_id exp6) match glob pattern "\n> "? no
expect: timed out
send: sending "quit\n" to { exp6 }
なぜ一致しないのですか?新しいプロンプト(コマンド完了)の出現をどのように検出しますか?
答え1
言語では、expect
tcl
文字列の使用と引用には違いがあります。次の2つの例でこれを確認できます。""
{}
$ expect -c 'puts "a\nb"'
a
b
~ $ expect -c 'puts {a\nb}'
a\nb
globパターンは、一致{\n> }
するが\n
特別にエスケープされたと解釈されない4つの文字で構成されています。パターンを使用すると、"\n> "
一致が機能します。あるいは、デフォルトのglobパターンの代わりにフラグを使用する-re
こともでき、両方の文字は正規表現コードによってエスケープ文字として解釈されます-re {\n> }
。
答え2
長すぎます。ロゴを追加してください-ex
。
ここで重要なのはexpect
仕事を簡単にしましょういくつかのコマンド(expect
/ interact
)に複雑なパラメータを渡します。
単一のリストに含まれる引数(バリアントとインタラクションの予測)を許可するコマンドは、経験的な方法を使用して、リストが実際に1つの引数であるか複数の引数であるかを決定します。リストが実際に単一の引数を表し、その引数の間に空白以外の文字を含む\ nが複数含まれている場合にのみ、経験的方法は失敗します。そうではありませんが、「-nobrace」パラメータを使用すると、個々の引数を単一の引数として扱うように強制できます。おそらく、これはマシンで生成されたExpectコードで使用できます。同様に、-braceは単一の引数が複数のモード/タスクで処理されるように強制します。
(expectコマンドの説明で)Expectステートメント全体のパラメータに複数の行が必要な場合は、各行がバックスラッシュで終わるのを防ぐために、すべてのパラメータを1行に「中括弧」で囲むことができます。この場合、中括弧にもかかわらず、一般的なTcl置換が依然として発生します。
ここで例を見てみましょう。
#!/usr/bin/env bash
set -eu
f() {
echo line 1
sleep 1
echo line 2
}
export -f f
echo '
spawn bash -c f
expect {
{line 1} {puts 1}
{line 2} {puts 2}
}
expect \
{line 1} {puts 1} \
{line 2} {puts 2}
' | expect
出力:
spawn bash -c f
line 1
1
line 2
2
私が見つけたリポジトリでは、経験的最新のコミット(2014年5月)では、次のようになります。次のように:引数が渡され、最初の非空白文字の前に改行文字がある場合、引数は1つに囲まれた複数の引数と見なされます。