1

I'm using subprocess to run a script from within python. I tried this

option 1

password = getpass.getpass()
from subprocess import Popen, PIPE, check_call  
proc=Popen([command, option1, option2, etc...], stdin=PIPE, stdout=PIPE, stderr=PIPE)  
proc.stdin.write(password)  
proc.stdin.flush()  
stdout,stderr = proc.communicate()  
print stdout  
print stderr  

and this

option 2

password = getpass.getpass()
subprocess.call([command, option1, option2, etc..., password])

Neither of them work, that is, the password is not sent to the process. If I use option 2 and do not provide password, the subprocess asks me for it and everething works.

Bob
  • 10,741
  • 27
  • 89
  • 143
  • You probably need to use [pexpect](https://github.com/pexpect/pexpect) for this. Generally you can't send passwords via stdin. – dano Aug 07 '14 at 18:18
  • other people seem to have used it http://stackoverflow.com/questions/2387731/use-subprocess-to-send-a-password – Bob Aug 07 '14 at 18:19
  • Right, that's what I'm saying. All the questions asking how to send a password via `stdin` get answered with "use pexpect". – dano Aug 07 '14 at 18:21
  • could you post an example with pexpect? I read the docs but I'm not sure how to translate the code above – Bob Aug 07 '14 at 18:22
  • Bob, see here: https://github.com/pexpect/pexpect/blob/master/examples/passmass.py – Mahmoud Abdelkader Aug 07 '14 at 18:28

2 Answers2

5

Here's a very basic example of how to use pexpect for this:

import sys
import pexpect
import getpass

password = getpass.getpass("Enter password:")

child = pexpect.spawn('ssh -l root 10.x.x.x "ls /"')
i = child.expect([pexpect.TIMEOUT, "password:"])
if i == 0:
    print("Got unexpected output: %s %s" % (child.before, child.after))
    sys.exit()
else:
    child.sendline(password)
print(child.read())

Output:

Enter password:

bin
boot
dev
etc
export
home
initrd.img
initrd.img.old
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
selinux
srv
sys
tmp
usr
var
vmlinuz
vmlinuz.old

There are more detailed examples here.

dano
  • 91,354
  • 19
  • 222
  • 219
  • keep getting "got as pattern, must be one of , pexpect.EOF, pexpect.TIMEOUT" – Bob Aug 07 '14 at 18:39
  • 1
    @Bob What version of Python? Try replacing `"password"` with `u"password"`. – dano Aug 07 '14 at 18:41
  • ok... so now, in my case there may be more text than just 'password'. I tried '\w*password\w*' but it gets stuck. Did I do something wrong with re? – Bob Aug 07 '14 at 18:47
  • 1
    @Bob in my case the text is actually `"root@10.x.x.x's password:"` It just looks for the provided text anywhere in the output. It still works if I just provide `"passwor"`. – dano Aug 07 '14 at 18:49
  • and TIMEOUT tells it to stop after waiting for a certain number of seconds? – Bob Aug 07 '14 at 18:50
  • 1
    @Bob Yeah, that's there just in case something unexpected is in the output of the command you're running, so it doesn't hang forever. (Actually, I think the command will still timeout if you don't provide it, you'll just get an exception raised) You can also provide other strings to wait for, too. The return value of the `expect` call will be the index in the list of the output that matched. so, 0 for `TIMEOUT`, 1 for `password:` in the above example. – dano Aug 07 '14 at 18:51
0

You should be passing the password as a value to the communicate() function instead of stdin.write(), like so:

from getpass import getpass
from subprocess import Popen, PIPE

password = getpass("Please enter your password: ")
proc = Popen("command option1 option2".split(), stdin=PIPE, stdout=PIPE)
# Popen only accepts byte-arrays so you must encode the string
proc.communicate(password.encode())
double-beep
  • 5,031
  • 17
  • 33
  • 41
Josh Correia
  • 3,807
  • 3
  • 33
  • 50