1

This is really interesting. I have following scripts on my linux machine:

sleep.py

import time
from datetime import datetime
print(datetime.now())
time.sleep(20)
print('Over!')
print(datetime.now())

loop.py

import time
for i in range(20):
    time.sleep(1)
    print(i)

I can terminate them directly by ctrl+c if I login through PuTTY or git-bash. But when I trying to run the Python scripts on Windows console:

test.py

def ssh_pty_command(cmd, ip, username, passwd=None, key_filename=None):
    """run ssh.exec_command with realtime output and return exit_code."""
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        logging.debug('Connecting to remote server {}...'.format(ip))
        ssh.connect(ip, 22, username, password=passwd,
                    key_filename=key_filename, timeout=5)
        stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True)
        logging.info('ssh_In: {}'.format(cmd))
        # print '$: {}'.format(cmd)
        for line in iter(stdout.readline, ""):
            logging.info('ssh_Out: {}'.format(
                line.rstrip('\n').encode('utf-8')))
        for err in iter(stderr.readline, ""):
            logging.error('ssh_Error: {}'.format(
                err.rstrip().encode('utf-8')))
        exit_code = stdout.channel.recv_exit_status()
        logging.debug('Task exit with code {}.\n'.format(exit_code))
        return exit_code
    except Exception as err:
        logging.error('*** Caught SSH exception: %s: %s' %
                      (err.__class__, err))
        raise
    finally:
        ssh.close()

  ssh_pty_command('python loop.py',ip,username)
  ssh_pty_command('python sleep.py',ip,username)

When I press ctrl+c , the loop.py terminated immediately, but the sleep.py waits until the time.sleep(20) is finished and then terminate the execution. How can I terminate the sleep.py immediately?

Note I did try to use get_pty=True in my exec_command method in my function, but it didn't help. I guess it should have something to do with the signal sent by Paramiko, but not sure where to dig in...

Wayne
  • 23
  • 5
  • 1
    It's not really clear what do you do to terminate the commands. Do press Ctrl+C in the **local** Python console window? – Martin Prikryl Mar 14 '18 at 07:23
  • @MartinPrikryl, yes, that's what I do exactly! Sorry for the confusion, I find no where to edit my question again. – Wayne Mar 14 '18 at 07:52

1 Answers1

0

Ctrl+C signals an interrupt. Python interpreter checks for the interrupt regularly, and raises KeyboardInterrupt exception, when it detects one.

When Paramiko is waiting for an incoming data on a socket, the checking for interrupts is probably suspended (just guessing). So if a remote command is not producing any output, you cannot break the local script.

Your loop.py produces an output using print(i), so your local Python script can be interrupted at the moment it's processing the output.

In any case, it's not the remote script that cannot be interrupted, it's the local script. So it has probably nothing to do with time.sleep as such.

See also:


If you actually do not want to wait for the command to finish, your question is not really about Python (nor Paramiko), but about Linux. See Execute remote commands, completely detaching from the ssh connection.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • Oh man, you are right! When I delete the print(i) in loop.py, it also fails, it has nothing to do with time.sleep. – Wayne Mar 14 '18 at 09:07
  • But the question remain the same, how can I terminate any long run script without data on a socket? – Wayne Mar 14 '18 at 09:08
  • Try checking `.readable` before `.readline`, not to block the script, when there's no data (and sleep local script for a short period, when `!readable`). – Martin Prikryl Mar 14 '18 at 09:11
  • The problem is that I don't have much control of the local scripts, it could be written by someone else. What I want to do is simply terminate the python scripts without waiting remotely via paramiko. – Wayne Mar 14 '18 at 09:33
  • **But it's the local script that prevents the interruption!** You should not try to fix that from the remote script. You can of course hack it by producing sopme output (as your `loop.py` does). But that's just a hack in a response to a particular known behavior of the local script. - And note that you can use `Ctrl+Break` to forcefully terminate local script. – Martin Prikryl Mar 14 '18 at 10:08
  • here is the story... the script may executing long time task which is in fact un needed if anything goes wrong already, and I tried to terminate the process as early as possible in my debugging environment. – Wayne Mar 14 '18 at 10:41
  • Sorry, I do not understand. – Martin Prikryl Mar 14 '18 at 10:44
  • Well, I use python on my window machine to do some automated work on linux machine(I start some python scripts on the linux machine via this ssh.exec_command function ), for some reasons, I want to terminate the automated work directly, not waiting for the blocking code to be done. Thanks for your patient, I'm new to python and programming stuff, but I really tried a lot other method and need some guidance now. – Wayne Mar 15 '18 at 01:57
  • Your question says *"how to terminate"*, not *"how to run script and not wait for it to finish"*. Anyway, if you do not want to wait, your question is not really about Python (nor Paramiko), but about Linux. See [Execute remote commands, completely detaching from the ssh connection](https://unix.stackexchange.com/q/30400/119732). – Martin Prikryl Mar 15 '18 at 04:23