MrCskncn
MrCskncn

Reputation: 327

Multiple inputs in a Python Subprocess PIPE (with stdin or communicate)

I've been looking for an answer to the question above.

The Popen command should not return anything, its simply asking for "do you want to continue?" (yes) and the "admin password" taken from a local database.

Current code state is: Everything works fine but asks me the second input, first input passes through.

So, I'm open to suggestions and willing to try your helps. Any help would be appreciated.

        #Input 1
        p = Popen(["foo", "bar"], stdin=PIPE, universal_newlines=True)
        try:
            p.stdin.write('yes' + linesep)
        except IOError as e:
            if e.errno == errno.EPIPE or e.errno == errno.EINVAL:
                break
            else:
                raise
        p.stdin.flush()
        #Input 2
        try:
            p.stdin.write(KeyPass + linesep)
        except IOError as e:
            if e.errno == errno.EPIPE or e.errno == errno.EINVAL:
                break
            else:
                raise
        p.stdin.flush()
        p.stdin.close()
        p.wait()

Upvotes: 1

Views: 1641

Answers (3)

zimplex
zimplex

Reputation: 41

you can use communicate() instead of write()

p.communicate(input='{}\n{}'.format('yes', KeyPass).encode('utf-8'))

Upvotes: 0

jfs
jfs

Reputation: 414795

its simply asking for "do you want to continue?" (yes) and the "admin password"

To answer "yes" if the child process asks "...continue?" and to write a password when prompted:

import pexpect # $ pip install pexpect

output, status = pexpect.run('foo bar',
    events={r'continue\?': 'yes\n', 'password': 'p4$$W__rd\n'},
    withexitstatus=1)

pexpect makes sure that even if the child process writes/reads directly to/from a terminal (outside process' stdout/stdin), you'll see its output and it receives your input.

Upvotes: 0

abarnert
abarnert

Reputation: 366063

It does not echo the password neither asterisks.

This means you can't drive it through stdin. What you're trying to do is just not possible that way.

See if there's another way to give it a password—maybe on the command line, or through the environment—or to avoid giving it a password (e.g., with ssh you can exchange keys instead of passing passwords).

If not, your only option is to give it a pseudo-TTY instead of a regular pipe. (Even this isn't guaranteed to work, but it's likely to work, and worth trying.)

There are three ways to do that from Python: os.openpty, os.forkpty, and the pty module. In theory, forkpty is the most platform-specific, but in practice, because pty is only tested on Linux, and openpty requires you to do other platform-specific stuff to actually do anything useful with it, I'd start with forkpty. The code looks like this:

pid, fd = os.forkpty()
if not pid:
    # We're in the child here, but we still have to launch the program
    os.execlp('foo', 'bar')
# This code is still in the parent.

Now, the parent can use os.read(fd) and os.write(fd) to talk to the child, and the child will see it as coming from the TTY. And when the child is done, you have to os.waitpid(pid) it. Just remember that you're dealing with low-level file I/O here—no decoding to Unicode, no universal newlines, and, most of all, no buffering. This can be tricky to deal with, but you have to deal with it.

Or, of course, you can use a library like pexpect, which can use a PTY and hide all the details from you. I'm not sure why you're resistant to this idea, but when you get frustrated trying to deal with forkpty, maybe give it another chance.

Upvotes: 1

Related Questions