Running interactive commands in Paramiko
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.
Executing commands of interactive tool and reading their output with Paramiko
The command that you are executing is interactive. When started, it waits for subcommands. While you execute it and wait for the command to finish (by calling readlines
). What never happens.
You have to feed the subcommands to your command to have it do something.
See Pass input/variables to command/script over SSH using Python Paramiko.
You will also have to make the command quit (by sending a subcommand like exit
/quit
/bye
).
how to interact with Paramiko's interactive shell session?
I imported a file, interactive.py, found on Paramiko's GitHub. After importing it, I just had to change my code to this:
try:
import interactive
except ImportError:
from . import interactive
...
...
channel.invoke_shell()
interactive.interactive_shell(channel)
sshClient.close()
Combining interactive shell and recv_exit_status method using Paramiko
SSHClient.recv_exit_status
signals that the channel has closed.
The "shell" channel closes only when the shell closes. A "shell" is a black box with input and output. Nothing else. There's no way SSH, let alone Paramiko, will be able to tell anyhow, when individual commands in the shell have finished. The shell_chan.send('something')
is not a signal to SSH to execute a command. It simply sends an arbitrary input to the "shell". Nothing else. It's totally at the shell disposition how the input is interpreted. All that the SSH/Paramiko gets back is an arbitrary unstructured output. Paramiko cannot interpret it anyhow for you.
If you need to be able to tell when a command has finished, you need to use "exec" channel (SSHClient.exec_command
method in Paramiko). You should not use the "shell" channel, unless you are implementing an interactive SSH terminal client, like PuTTY (or in rare cases, when you talk to an limited SSH server that does not implement the "exec" channel, as it often the case with dedicated devices, such as routers, switches, etc).
For related questions, see:
- Execute multiple dependent commands individually with Paramiko and find out when each command finishes
- How to get each dependent command execution output using Paramiko exec_command
- Use the same SSH object to issue "exec_command()" multiple times in Paramiko
- Execute (sub)commands in secondary shell/command on SSH server in Paramiko
- Invoke multiple commands inside a process in interactive ssh mode
- Executing command using Paramiko exec_command on device is not working
- What is the difference between exec_command and send with invoke_shell() on Paramiko?
Implement an interactive shell over ssh in Python using Paramiko?
import paramiko
import re
class ShellHandler:
def __init__(self, host, user, psw):
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect(host, username=user, password=psw, port=22)
channel = self.ssh.invoke_shell()
self.stdin = channel.makefile('wb')
self.stdout = channel.makefile('r')
def __del__(self):
self.ssh.close()
def execute(self, cmd):
"""
:param cmd: the command to be executed on the remote computer
:examples: execute('ls')
execute('finger')
execute('cd folder_name')
"""
cmd = cmd.strip('\n')
self.stdin.write(cmd + '\n')
finish = 'end of stdOUT buffer. finished with exit status'
echo_cmd = 'echo {} $?'.format(finish)
self.stdin.write(echo_cmd + '\n')
shin = self.stdin
self.stdin.flush()
shout = []
sherr = []
exit_status = 0
for line in self.stdout:
if str(line).startswith(cmd) or str(line).startswith(echo_cmd):
# up for now filled with shell junk from stdin
shout = []
elif str(line).startswith(finish):
# our finish command ends with the exit status
exit_status = int(str(line).rsplit(maxsplit=1)[1])
if exit_status:
# stderr is combined with stdout.
# thus, swap sherr with shout in a case of failure.
sherr = shout
shout = []
break
else:
# get rid of 'coloring and formatting' special characters
shout.append(re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]').sub('', line).
replace('\b', '').replace('\r', ''))
# first and last lines of shout/sherr contain a prompt
if shout and echo_cmd in shout[-1]:
shout.pop()
if shout and cmd in shout[0]:
shout.pop(0)
if sherr and echo_cmd in sherr[-1]:
sherr.pop()
if sherr and cmd in sherr[0]:
sherr.pop(0)
return shin, shout, sherr
Related Topics
How to Display Tooltips in Tkinter
What Is the Maximum Float in Python
How to Determine the Length of Lists in a Pandas Dataframe Column
Pandas: Filtering Multiple Conditions
Extrapolate Values in Pandas Dataframe
Python Scope: "Unboundlocalerror: Local Variable 'C' Referenced Before Assignment"
How to Add a Qvideowidget in Qt Designer
How to Set Window Size in Selenium Chrome Python
Intercepting Stdout of a Subprocess While It Is Running
Python - Pygame Error When Executing Exe File
Exif Manipulation Library for Python
How to Get "Python -M Venv" to Directly Install Latest Pip Version