1

I am running a series of remote shell commands leveraging the Paramiko library.

The final command requires user input at the end device and I do not need to wait for execution to complete; however, I cannot proceed until the last command completes.

Code:

k = paramiko.RSAKey.from_private_key_file("....", password="....")
conn = paramiko.SSHClient()
conn.connect(hostname=ip_addr, username="root", pkey=k, password="....")

commands = ["chmod 755 /tmp/evtool", "nohup /tmp/test.sh >/dev/null 2>&1"]

for command in commands:
    stdin, stdout, stderr = conn.exec_command(command)
conn.close()

The command in question is :

nohup /tmp/test.sh >/dev/null 2>&1

No matter how I attempt to run it :

/tmp/test.sh
/tmp/test.sh&

The application waits for the process to complete; however the completion could take hours and the pass / fail is displayed on the remote unit, I do not need to wait for a result.

I have dozens of remote units and the above function is called from a loop that iterates through the unit ip addresses and makes the connection / runs the test.

Any ideas how not to wait for the last process to complete?

Thanks, Dan.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Dan G
  • 366
  • 1
  • 3
  • 18

1 Answers1

0

This is not really a Python or Paramiko question. It's a Linux shell question.

According to Getting ssh to execute a command in the background on target machine, it seems that you need both nohup and &.


Though from your comments, it looks like you actually want to wait for the command to complete. You just maybe want to run multiple command in parallel.

Actually the SSHClient.exec_command does not wait. So I'm not sure exactly what your question is.

But indeed, waiting for multiple commands in parallel while collecting their output, if that's what you want, is not that trivial. Something like this works:

commands = [
    "for i in {1..10}; do echo \"0 o:$i\"; sleep 1; echo \"0 e:$i\" >&2; sleep 1; done",
    "for i in {1..10}; do echo \"1 o:$i\"; sleep 1; echo \"1 e:$i\" >&2; sleep 1; done",
    "for i in {1..10}; do echo \"2 o:$i\"; sleep 1; echo \"2 e:$i\" >&2; sleep 1; done",
]

channels = []
for command in commands:
    print(f"starting {len(channels)}")
    stdin, stdout, stderr = ssh.exec_command(command)
    channels.append(stdout.channel)

while any(x is not None for x in channels):
    for i in range(len(channels)):
        channel = channels[i]
        if channel is not None:
            # To prevent losing output at the end, first test for exit, then for output
            exited = channel.exit_status_ready()
            while channel.recv_ready():
                s = channel.recv(1024).decode('utf8')
                print(f"#{i} stdout: {s}")
            while channel.recv_stderr_ready():
                s = channel.recv_stderr(1024).decode('utf8')
                print(f"#{i} stderr: {s}")
            if exited:
                print(f"#{i} done")
                channels[i] = None
    time.sleep(0.1)
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992