48

I'm trying to run an interactive command through paramiko. The cmd execution tries to prompt for a password but I do not know how to supply the password through paramiko's exec_command and the execution hangs. Is there a way to send values to the terminal if a cmd execution expects input interactively?

ssh = paramiko.SSHClient()
ssh.connect(server, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("psql -U factory -d factory -f /tmp/data.sql")

Does anyone know how this can addressed? Thank you.

shahjapan
  • 13,637
  • 22
  • 74
  • 104
Sharmila
  • 1,637
  • 2
  • 23
  • 30
  • 3
    The question is old but for the people who still come here via google search i want to give them this.The key is to get your own **channel** [Executing Interactive Commands in Python through Paramiko Part 1](https://www.youtube.com/watch?v=Jc2l-n_GYPI) [Executing Interactive Commands in Python through Paramiko Part 2](https://www.youtube.com/watch?v=lLKdxIu3-A4) In this two videos it's explained how to run interactive commands via paramiko especially the second video is great and probably what you need. – Mino_e Jan 26 '15 at 16:50

7 Answers7

32

The full paramiko distribution ships with a lot of good demos.

In the demos subdirectory, demo.py and interactive.py have full interactive TTY examples which would probably be overkill for your situation.

In your example above ssh_stdin acts like a standard Python file object, so ssh_stdin.write should work so long as the channel is still open.

I've never needed to write to stdin, but the docs suggest that a channel is closed as soon as a command exits, so using the standard stdin.write method to send a password up probably won't work. There are lower level paramiko commands on the channel itself that give you more control - see how the SSHClient.exec_command method is implemented for all the gory details.

scy
  • 7,132
  • 2
  • 27
  • 35
James Brady
  • 27,032
  • 8
  • 51
  • 59
  • 6
    And, for those of you who got here wanting to only see what the output of a command might be, some code might be: `(stdin, stdout, stderr) = Client.exec_command('ls -la') print("\nstdout is:\n" + stdout.read() + "\nstderr is:\n" + stderr.read()) ` – Paul Hoffman Apr 11 '11 at 17:46
  • 3
    Fixed broken link. – scy Nov 16 '17 at 19:34
12

I had the same problem trying to make an interactive ssh session using ssh, a fork of Paramiko.

I dug around and found this article:

Updated link (last version before the link generated a 404): http://web.archive.org/web/20170912043432/http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/

To continue your example you could do

ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("psql -U factory -d factory -f /tmp/data.sql")
ssh_stdin.write('password\n')
ssh_stdin.flush()
output = ssh_stdout.read()

The article goes more in depth, describing a fully interactive shell around exec_command. I found this a lot easier to use than the examples in the source.

Original link: http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/

jrd1
  • 10,358
  • 4
  • 34
  • 51
afrosteve
  • 891
  • 2
  • 11
  • 16
6
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(server_IP,22,username, password)


stdin, stdout, stderr = ssh.exec_command('/Users/lteue/Downloads/uecontrol-CXC_173_6456-R32A01/uecontrol.sh -host localhost ')
alldata = ""
while not stdout.channel.exit_status_ready():
   solo_line = ""        
   # Print stdout data when available
   if stdout.channel.recv_ready():
      # Retrieve the first 1024 bytes
      solo_line = stdout.channel.recv(1024) 
      alldata += solo_line
   if(cmp(solo_line,'uec> ') ==0 ):    #Change Conditionals to your code here  
     if num_of_input == 0 :
      data_buffer = ""    
      for cmd in commandList :
       #print cmd
       stdin.channel.send(cmd)        # send input commmand 1
      num_of_input += 1
     if num_of_input == 1 :
      stdin.channel.send('q \n')      # send input commmand 2 , in my code is exit the interactive session, the connect will close.
      num_of_input += 1 
print alldata
ssh.close()              

Why the stdout.read() will hang if use dierectly without checking stdout.channel.recv_ready(): in while stdout.channel.exit_status_ready():

For my case ,after run command on remote server , the session is waiting for user input , after input 'q' ,it will close the connection . But before inputting 'q' , the stdout.read() will waiting for EOF,seems this methord does not works if buffer is larger .

  • I tried stdout.read(1) in while , it works
    I tried stdout.readline() in while , it works also.
    stdin, stdout, stderr = ssh.exec_command('/Users/lteue/Downloads/uecontrol')
    stdout.read() will hang
kevin yu
  • 89
  • 1
  • 3
  • 1
    This should be made a separate question if you need an answer (as this is an old question). Or atleast it should be a comment on the question or one of the answers. It cannot be an answer by itself. – Sharmila Sep 30 '16 at 04:59
  • Excellent answer which helped me forward. For who it might interest: I had problem reading the last line I needed from the command in a multi-threaded application. Stuff just seemed to hang. But then I started issuing ssh_stdout.channel.close() and then doing final read with ssh_stdout.channel.recv(1000) . Boom, no more hangs! (Of course everyone should consider if this method is applicable to their code.) – Janne Paalijarvi Jul 16 '23 at 08:18
5

You need Pexpect to get the best of both worlds (expect and ssh wrappers).

ax25
  • 67
  • 1
  • 2
  • I would recommend this as well. Here is an example that controls multiple servers at the same time but it could easily be used on just one. https://github.com/pexpect/pexpect/blob/master/examples/hive.py – JerodG Aug 30 '19 at 19:03
3

I'm not familiar with paramiko, but this may work:

ssh_stdin.write('input value')
ssh_stdin.flush()

For information on stdin:

http://docs.python.org/library/sys.html?highlight=stdin#sys.stdin

monkut
  • 42,176
  • 24
  • 124
  • 155
  • 4
    NOTE: Always make sure to flush() any buffer you're writing to the way this example correctly shows; forgetting (or not knowing) to do this is a common cause for frustration. – aculich Nov 28 '11 at 09:08
0

Take a look at example and do in similar way

(sorce from http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/):

    ssh.connect('127.0.0.1', username='jesse', 
        password='lol')
    stdin, stdout, stderr = ssh.exec_command(
        "sudo dmesg")
    stdin.write('lol\n')
    stdin.flush()
    data = stdout.read.splitlines()
    for line in data:
        if line.split(':')[0] == 'AirPort':
            print line
Paweł Wojtal
  • 330
  • 5
  • 11
-1

You can use this method to send whatever confirmation message you want like "OK" or the password. This is my solution with an example:

def SpecialConfirmation(command, message, reply):
    net_connect.config_mode()    # To enter config mode
    net_connect.remote_conn.sendall(str(command)+'\n' )
    time.sleep(3)
    output = net_connect.remote_conn.recv(65535).decode('utf-8')
    ReplyAppend=''
    if str(message) in output:
        for i in range(0,(len(reply))):
            ReplyAppend+=str(reply[i])+'\n'
        net_connect.remote_conn.sendall(ReplyAppend)
        output = net_connect.remote_conn.recv(65535).decode('utf-8') 
    print (output)
    return output

CryptoPkiEnroll=['','','no','no','yes']

output=SpecialConfirmation ('crypto pki enroll TCA','Password' , CryptoPkiEnroll )
print (output)
creyD
  • 1,972
  • 3
  • 26
  • 55