What is the difference between exec_command and send with invoke_shell() on Paramiko?
The difference is that invoke_shell
uses SSH shell
channel, while exec_command
uses SSH exec
channel.
What that really means to you as a user/developer really depends on the SSH server, not on Paramiko itself.
In common *nix OpenSSH server:
The
shell
channel executes a login shell (as if you login with SSH terminal client). The shell will then present a command prompt and wait for client/user to type the commands. The purpose of theshell
channel is to implement an interactive shell session. So basically it's legitimate use is an implementation of an SSH terminal client. That is something one will do very very rarely. If you do, you typically want to use terminal emulation (Paramikoinvoke_shell
does that unconditionally, but actually it's possible to open theshell
channel without the terminal emulation).The
shell
channel is obviously used by SSH terminal clients (like OpenSSHssh
or PuTTY), under normal circumstances.The
shell
channel is a black box with an input and output. The input and output have no structure. If you for example execute a command by sending it to the input, you will never be able to tell when it ended. If you send two commands to input queue, you won't be able to distinguish what output comes from what command.The
exec
command takes a command as an "argument" and executes it in an isolated environment – still via user's default shell, but not as a "login" shell, what may cause significant differences in the command execution.For a typical example of such difference, see Some Unix commands fail with "<command> not found", when executed using Python Paramiko exec_command.
The purpose of the
exec
channel is automating a command execution. So typically you do not want to use a terminal emulation, to avoid the command to do fancy stuff like pagination, coloring and mainly interactive confirmations. That's why the default value ofget_pty
isFalse
.The
exec
channel is used by OpenSSHssh
or PuTTYplink
, when you specify a command to execute on its command line:ssh user@host command
With less common SSH servers, the difference can be even more significant. Some servers may even not support one of the channels. It is also quite common that they seemingly support both, but one of them (typically the exec
) is completely broken.
See Executing command using Paramiko exec_command on device is not working.
There's a similar question for Java/JSch:
What is the difference between the 'shell' channel and the 'exec' channel in JSch
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?
Execute multiple dependent commands individually with Paramiko and find out when each command finishes
It seems that you want to implement an interactive shell, yet you need to control individual commands execution. That's not really possible with just SSH interface. "shell" channel in SSH is black box with an input and output. So there's nothing in Paramiko that will help you implementing this.
If you need to find out when a specific command finishes or where an output of a specific command ends, you need to use features of a shell.
You can solve that by inserting a unique separator (string) in between and search for it in the channel output stream. With a common *nix shells something like this works:
channel = ssh.invoke_shell()
channel.send('cd /mytargetRep\n')
channel.send('echo unique-string-separating-output-of-the-commands\n')
channel.send('./executeWhatIWant\n')
Though I do not really think that you need that very often. Most commands that are needed to make a specific commands working, like cd
or set
, do not really output anything.
So in most cases you can use SSHClient.exec_command
and your code will be a way simpler and more reliable:
Execute multiple commands in Paramiko so that commands are affected by their predecessors
Even if you need to use something seemingly complex like su
/sudo
, it is still better to stick with SSHClient.exec_command
:
Executing command using "su -l" in SSH using Python
For a similar question, see:
Combining interactive shell and recv_exit_status method using Paramiko
Related Topics
How to Get Stable Results with Tensorflow, Setting Random Seed
Downloading a Directory Tree with Ftplib
Attributeerror: 'Pandasexprvisitor' Object Has No Attribute 'Visit_Ellipsis', Using Pandas Eval
Suppress Insecurerequestwarning: Unverified Https Request Is Being Made in Python2.6
Use Python Requests to Download CSV
Plot a Bar Using Matplotlib Using a Dictionary
Numpy: Fix Array with Rows of Different Lengths by Filling the Empty Elements with Zeros
Flask Importerror: No Module Named Flask
Beautifulsoup:Difference Between .Find() and .Select()
Correct Style for Python Functions That Mutate the Argument
Why Does Indexing Numpy Arrays with Brackets and Commas Differ in Behavior
Weighted Choice Short and Simple
Differencebetween Exec_Command and Send with Invoke_Shell() on Paramiko
Select Multiple Ranges of Columns in Pandas Dataframe
Django Model Field Default Based Off Another Field in Same Model