I want to run a command which prompts me to enter yes/no or y/n or whatever. If I just run the command local("my_command")
then it stops and asks me for input. When I type what is needed, script continues to work. How can I automatically respond to the prompt?

- 3,702
- 6
- 34
- 49
-
possible duplicate of [How to get Fabric to automatically (instead of user-interactively) interact with shell commands? Combine with pexpect?](http://stackoverflow.com/questions/8291380/how-to-get-fabric-to-automatically-instead-of-user-interactively-interact-with) – Steffen Opel May 07 '12 at 16:28
-
1@aemdy could you please change the answer to be the one suggested by Timothée Jeannin. I have seen several other questions like this, and the currently selected answer is outdated. It would make it much easier for folks to get the right answer :). – Breedly Feb 05 '17 at 15:08
6 Answers
Starting from version 1.9
, Fabric includes a way of managing this properly.
The section about Prompts in the Fabric documentation says:
The prompts dictionary allows users to control interactive prompts. If a key in the dictionary is found in a command’s standard output stream, Fabric will automatically answer with the corresponding dictionary value.
You should be able to make Fabric automatically answer prompts like this:
with settings(prompts={'Do you want to continue [Y/n]? ': 'Y'}):
run('apt-get update')
run('apt-get upgrade')

- 9,652
- 2
- 56
- 65
-
3
-
3@aemdy This should really be the accepted answer at this point, works out of the box with no issues. – Nathan Cox Dec 14 '15 at 19:09
-
1Tip: Your prompts dictionary keys are matched using a built-in Fabric function io._endswith. If you can't figure out why your patterns aren't matching, it might be because you forgot to include a space at the end. For example "UNIX password: " or "New password: " or "Retype new password: " – scottwed Jun 07 '16 at 18:47
-
-
I'm struggling to figure out how I could use this to, first, trigger a sequence of actions, and only *then* reply to the prompt. Is there any way? – Shon Aug 18 '16 at 00:59
-
1Fabric uses `.endswith` for its check, so make sure you include trailing spaces in the string you use as a key in the `prompts` dictionary. – Christian Long Nov 21 '16 at 16:22
-
I find that there is a white space after '[Y/n]? ', is it necessary or not? – Kingname Dec 12 '16 at 07:31
-
1Does this work with `local()` function? I tried something simple, like `with settings(prompts={'Continue? ': 'Y'}): local('read -p "Continue? " var', capture=True)` and it was blocked on the prompt. Update: It looks like input was still connected to console :( – haridsv May 17 '17 at 11:46
-
1To answer my own question from above, it looks like prompts are handled in ssh io while `local` is just a simple wrapper on top of `Popen` so this won't work. I guess we need to use `pexpect`. – haridsv May 17 '17 at 11:55
I have used simple echo pipes to answer prompts with Fabric.
run('echo "yes\n"| my_command')

- 441
- 2
- 3
Note: this answer is several years old, and in the mean time fabric has (interestingly similar looking) implementation of this. See the answer by @timothée-jeannin below.
See 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 adds answering to prompts to fabric with use of pexpect

- 1
- 1

- 3,169
- 4
- 32
- 55
-
Cool project, but it'd be better if it could not have to rely on putting a python file on the server. Need to check this out more and see if I can assist. – Morgan May 08 '12 at 02:34
-
1Thanks Morgan, I agree. I have suggested something on the fabric list, but got no response so far, and ended up writing fexpect which cost me less time than getting into the internals of Fabric. – Jasper van den Bosch May 08 '12 at 10:38
-
Right, I think I saw that, but didn't perhaps grok the intent. I'm pretty interested in pushing this further, and have had some experience in Fabric internals, and before I found Fabric, pxssh/pexpect. – Morgan May 08 '12 at 21:37
-
-
it doesnt work for me: http://pastebin.com/vAPwVxaR code: http://pastebin.com/HFUJkb6J – Nov 24 '13 at 16:27
-
Please post this as a new question and send it to me. Also include your python code if possible – Jasper van den Bosch Nov 25 '13 at 17:59
-
1The blog post link currently unavailable, "ilogue.com is for sale"... Here's the archived page: http://web.archive.org/web/20140624141333/http://ilogue.com/jasper/blog/fexpect--dealing-with-prompts-in-fabric-with-pexpect/ – FooF Dec 01 '15 at 05:50
-
-
Fabric has awesome built in support for this now. Check a few comments down for the 31 point answer. – Breedly Feb 05 '17 at 15:06
-
1@Breedly I have added a note to this answer as a heads up for visitors – Jasper van den Bosch Feb 05 '17 at 19:08
In Fabric 2.1, this can be accomplished using the auto-respond example that is available through the invoke package (a dependency of Fabric 2.1):
>>> 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>
Note that this is not limited to sudo passwords and can be used anywhere where you have a pattern to match for and a canned response (that may not be a password).
There are a couple of tips:
pty=True
is NOT necessary but could be important because it makes the flow seem more realistic. e.g. if you had a prompt expecting a yes/no answer to proceed, without it(pty=True
) your command would still run; except, your choice/input(specified byresponse
) won't be shown as typed as the answer as one might expect- The
pattern
specified within theResponder
can often include spaces at the end of the line so try adding spaces when thewatcher
doesn't seem to match. According to the note discussed at the end of the watcher docs:
The pattern argument to Responder is treated as a regular expression, requiring more care (note how we had to escape our square-brackets in the above example) but providing more power as well.
So, don't forget to escape (using backslashes) where necessary.
To expand a bit on Timothée's excellent answer, here's the code that Fabric uses when checking the prompts
dictionary.
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
Fabric uses .endswith
for its check, so make sure you include trailing spaces in the string you use as a key in the prompts
dictionary.
For example - let's say you are trying to automate the Django test database prompt
Type 'yes' if you would like to try deleting the test database 'test_my_app', or 'no' to cancel:
All we need is enough of the end of the prompt so that it is unique. Include trailing spaces.
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,
)
)

- 1
- 1

- 10,385
- 6
- 60
- 58
Putting this as an answer though its a comment from @BobNadler
run("yes | my_command");

- 593
- 2
- 10
- 22