Execute Multiple Dependent Commands Individually with Paramiko and Find Out When Each Command Finishes

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

How to get each dependent command execution output using Paramiko exec_command

The only solution is (as @Barmar already suggested) to insert unique separator between individual commands. Like:

pwd && echo "end-of-pwd" && cd /foo && echo "end-of-cd" && ls -l && echo "end-of-ls"

And then look for the unique string in the output.


Though imo, it is much better to simply separate the commands into individual exec_command calls. Though I do not really think that you need to execute multiple commands in a row often. Usually you only need something like, cd or set, and these commands do not really output anything.

Like:

  1. pwd
  2. ls -la /foo (or cd /foo && ls -la)

For a similar questions, see:

  • Execute multiple dependent commands individually with Paramiko and find out when each command finishes (for "shell" channel)
  • Combining interactive shell and recv_exit_status method using Paramiko

Execute two commands in a row using one SSH object via paramiko

It's not

ssh.exec_command('command1' ; 'command2')

Should be

ssh.exec_command('command1 ; command2')

Reading command output with Paramiko invoke_shell/send/recv never finishes

Your code gets to the point, where the server stops waiting for another input. At the same time you wait for the server to output something. What it never will. That's called a deadlock.

You might have expected some kind of signal that the first command execution has finished. There's no such signal. You are using a "shell" (SSHClient.invoke_shell). The shell is a black box with an input and an output. There are no other signals except for the output, which you are reading already.

The "shell" should not be used to automate command execution. For command automation, there's the "exec" channel (SSHClient.exec_command in Paramiko).

Though I understand that with some special devices, what your server seems to be, you might not have any other option (see Executing command using Paramiko exec_command on device is not working). Moreover I'm not ever sure how the enable command works. Whether it's a command that has finished, or whether it started a kind of a new shell, which is still running and is waiting for subcommands.

So in the end all you can do is to parse the output, waiting for the command prompt (smg-ib-apl008-gen2 [ mgmt-sa ] #).


Yes, it's ugly. You are trying to automate something that was not intended for automation. Maybe your server has a better API then enable shell command, that would be nicer to automate. But that's for another question. From SSH/Python/Paramiko point of view, there's no better solution, if you need to stick with executing the enable command in the shell.


Related questions:

  • How to get each dependent command execution output using Paramiko exec_command
  • Execute multiple dependent commands individually with Paramiko and find out when each command finishes

Though they are about more regular servers, like Linux. So they won't really help. I'm linking them just to provide broader picture and context.

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?


Related Topics



Leave a reply



Submit