24

Is there a way to keep tracebacks from coming up when you hit Ctrl+c, i.e. raise KeyboardInterrupt in a Python script?

Mwiza
  • 4,494
  • 2
  • 33
  • 30
Kyle Hotchkiss
  • 9,348
  • 18
  • 51
  • 81

7 Answers7

40

Try this:

import signal
import sys
signal.signal(signal.SIGINT, lambda x, y: sys.exit(0))

This way you don't need to wrap everything in an exception handler.

scrutari
  • 1,058
  • 1
  • 15
  • 24
jleahy
  • 14,060
  • 5
  • 41
  • 63
  • 4
    It is fundamentally wrong to exit with status 0 given that `SIGINT` is triggered. The returned exit status must ideally be preserved, as if the exception were not caught. – Acumenus Jun 24 '17 at 15:20
  • Not entirely understanding lambda; can you explain the use of "x,y:" here instead of just "x:"? – Locane Jul 28 '17 at 06:25
  • @Locane it's because of [this](https://docs.python.org/3.7/library/signal.html#signal.signal), basically the second argument of signal.signal is a function 'handler' that takes two parameters. For clarity x and y could be renamed like this `signal.signal(signal.SIGINT, lambda signal_number, current_stack_frame: sys.exit(0))` – oidualc Aug 08 '17 at 10:47
  • I was trying to stop stack-traces when hitting Ctrl-C on /usr/bin/openstack, and this approach worked partially for me. Adding the try/except solution in a previous answer works most of the time, but I still get a stack-trace sometimes - maybe because /usr/bin/openstack is just a wrapper for a module? – Laurence Renshaw May 26 '21 at 09:53
30
import sys
try:
    # your code
except KeyboardInterrupt:
    sys.exit(0) # or 1, or whatever

Is the simplest way, assuming you still want to exit when you get a Ctrl+c.

If you want to trap it without a try/except, you can use a recipe like this using the signal module, except it doesn't seem to work for me on Windows..

Mwiza
  • 4,494
  • 2
  • 33
  • 30
agf
  • 148,965
  • 36
  • 267
  • 227
  • 3
    It is fundamentally wrong to exit with status 0 given that SIGINT is signaled. The returned exit status must ideally be preserved, as if the exception were not caught. The comment "or 1" is not good enough; an **exit code of 1 is expected**. – Acumenus Jun 24 '17 at 17:35
  • 3
    @A-B-B an exit code of 1 is expected if exiting the program with Ctrl-C isn't the standard, non-error way of exiting it. If this method of exiting represents success, then zero is the expected exit code. Just because it's maybe a bad idea to use Ctrl-C this way doesn't mean people don't (and I've used programs that do). – agf Jun 24 '17 at 22:08
  • 2
    Sure, but including an exit code of 0 as a default choice in your answer still seems iffy. – Acumenus Jun 24 '17 at 22:16
  • This seems to interfere with `input`, at least on my system. Try putting `input("Press enter to continue")` inside the `try` block. When you press enter, it just prints `^M` to stdout. [This](https://askubuntu.com/a/452576/269136) seems relevant. – LondonRob Dec 15 '20 at 10:19
  • @LondonRob I just tried it and it definitely works fine for me. Reading the other issue you linked, it doesn't seem to have anything to do with the code here. Are you saying if you try this with a bare `input` it works, but if you add the `try` it doesn't? I think something else must be different. – agf Dec 16 '20 at 22:22
  • @agf yes, on my system that's the case. The `try` is what makes the difference. Running `stty sane` makes it work again. I don't know what this does though! – LondonRob Dec 17 '20 at 11:09
7

Catch the KeyboardInterrupt:

try:
    # do something
except KeyboardInterrupt:
    pass
icktoofay
  • 117,602
  • 18
  • 233
  • 223
2

Catch it with a try/except block:

while True:
   try:
      print "This will go on forever"
   except KeyboardInterrupt:
      pass
Manny D
  • 18,454
  • 2
  • 26
  • 31
2
try:
    your_stuff()
except KeyboardInterrupt:
    print("no traceback")
ʇsәɹoɈ
  • 19,708
  • 6
  • 48
  • 58
1

Also note that by default the interpreter exits with the status code 128 + the value of SIGINT on your platform (which is 2 on most systems).

    import sys, signal

    try:
        # code...
    except KeyboardInterrupt: # Suppress tracebacks on SIGINT
        sys.exit(128 + signal.SIGINT) # http://tldp.org/LDP/abs/html/exitcodes.html
toksaitov
  • 171
  • 1
  • 4
  • 2
    If aborting say the shell command `sleep 10`, the exit code indeed is 130 on my system. However, the exit code for when `KeyboardInterrupt` is raised in Python is simply 1. Consider [this closed bug](https://bugs.python.org/issue14229). As such, I believe the answer to be inconsistent. – Acumenus Jun 24 '17 at 17:34
  • This is incorrect. Exiting with signal `SIGINT` is different from a exiting with code `128 + SIGINT`. They may show up as the same `$?` in your shell, but they are distinguishable in the underlying API and have different effects. For example, typically, a shell script will stop execution when a child exits with a signal and not when it exits with a code. – Anders Kaseorg Oct 05 '20 at 22:10
-4
import sys
try:
    print("HELLO")
    english = input("Enter your main launguage: ")
    print("GOODBYE")
except KeyboardInterrupt:
    print("GET LOST")
fuesika
  • 3,118
  • 6
  • 23
  • 32