Differencebetween Exec_Command and Send with Invoke_Shell() on Paramiko

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 the shell 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 (Paramiko invoke_shell does that unconditionally, but actually it's possible to open the shell channel without the terminal emulation).

    The shell channel is obviously used by SSH terminal clients (like OpenSSH ssh 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 of get_pty is False.

    The exec channel is used by OpenSSH ssh or PuTTY plink, 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



Leave a reply



Submit