web-dev-qa-db-ja.com

python fabricで自動的にプロンプ​​トに応答する方法は?

Yes/noまたはy/nなどの入力を促すコマンドを実行したい。コマンドlocal("my_command")を実行すると、停止して入力を求められます。必要なものを入力すると、スクリプトは引き続き機能します。プロンプトに自動的に応答するにはどうすればよいですか?

31
aemdy

バージョン1.9以降、Fabricにはこれを適切に管理する方法が含まれています。

Fabricドキュメントの プロンプトに関するセクション は次のように述べています。

プロンプトディクショナリを使用すると、インタラクティブなプロンプトを制御できます。辞書のキーがコマンドの標準出力ストリームで見つかった場合、Fabricは対応する辞書の値で自動的に応答します。

Fabricが次のようなプロンプトに自動的に応答できるようにする必要があります。

with settings(prompts={'Do you want to continue [Y/n]? ': 'Y'}):
    run('apt-get update')
    run('apt-get upgrade')
44

簡単なエコーパイプを使用して、Fabricでプロンプトに応答しました。

run('echo "yes\n"| my_command')
20
Henri Siponen

注:この回答は数年前のものであり、その間、ファブリックは(興味深いことに似たように)これを実装しています。以下の@timothée-jeanninの回答を参照してください。

参照してください https://stackoverflow.com/a/10007635/708221

pip install fexpect

from ilogue.fexpect import expect, expecting, run 

prompts = []
prompts += expect('What is your name?','John')
prompts += expect('Are you at stackoverflow?','Yes')

with expecting(prompts):
    run('my_command')

Fexpectはpexpectを使用してファブリックへのプロンプトへの応答を追加します

12

Timothéeの優れた答え を少し拡張するために、Fabricがprompts辞書を確認するときに使用する コード を次に示します。

def _get_Prompt_response(self):
    """
    Iterate through the request prompts dict and return the response and
    original request if we find a match
    """
    for tup in env.prompts.iteritems():
        if _endswith(self.capture, tup[0]):
            return tup
    return None, None

ファブリックは.endswithをチェックするため、prompts辞書のキーとして使用する文字列の末尾にスペースを含めてください。

たとえば、Django test database Promptを自動化しようとしているとしましょう。

テストデータベース「test_my_app」を削除する場合は「yes」、キャンセルする場合は「no」と入力します。

必要なのは、プロンプトが終了するだけで十分なので、それが一意になります。末尾のスペースを含めます。

Django_test_database_Prompt = "or 'no' to cancel: "
#         won't work without this trailing space ^

with settings(
    prompts={Django_test_database_Prompt : 'yes'}
):
    run('%s %s' % (virtualenv_python_path,
                   test_runner_file_path,
                  )
       )
4
Christian Long

@BobNadlerからのコメントですが、これを答えとして入れます

run( "yes | my_command");

2
MrBrightside

Fabric 2.1 では、これは、invokeパッケージ(Fabric 2.1の依存関係)から利用できる auto-respond example を使用して実現できます。

>>> from invoke import Responder
>>> from fabric import Connection
>>> c = Connection('Host')
>>> sudopass = Responder(
...     pattern=r'\[Sudo\] password:',
...     response='mypassword\n',
... )
>>> c.run('Sudo whoami', pty=True, watchers=[sudopass])
[Sudo] password:
root
<Result cmd='Sudo whoami' exited=0>

これはSudoパスワードに限定されず、一致するパターンと返信定型文(パスワードではない可能性がある)がある場所であればどこでも使用できることに注意してください。

いくつかのヒントがあります:

  1. pty=Trueはおそらく常に必要です
  2. pattern内で指定されたResponderは、多くの場合、行の末尾にスペースを含めることができるため、watcherが一致していないように見える場合はスペースを追加してみてください。
  3. watcher docs の最後で説明されているメモによると:

    Responderへのパターン引数は正規表現として扱われるため、より注意が必要ですが(上記の例で角括弧をエスケープする方法に注意してください)、より強力な機能も提供します。

    したがって、必要に応じて(バックスラッシュを使用して)エスケープすることを忘れないでください。

1
slaw