Python-捕获所有信号

Python-捕获所有信号,python,linux,signal-handling,Python,Linux,Signal Handling,在Linux下的python 2.6中,我可以使用以下方法来处理术语信号: import signal def handleSigTERM(): shutdown() signal.signal(signal.SIGTERM, handleSigTERM) 除了一次一个地设置信号外,是否有其他方法可以为流程接收的所有信号设置处理程序?您可以在信号模块中循环设置信号 for i in [x for x in dir(signal) if x.startswith("SIG")]:

在Linux下的python 2.6中,我可以使用以下方法来处理术语信号:

import signal
def handleSigTERM():
    shutdown()
signal.signal(signal.SIGTERM, handleSigTERM)    

除了一次一个地设置信号外,是否有其他方法可以为流程接收的所有信号设置处理程序?

您可以在信号模块中循环设置信号

for i in [x for x in dir(signal) if x.startswith("SIG")]:
  try:
    signum = getattr(signal,i)
    signal.signal(signum,sighandler)
  except (OSError, RuntimeError) as m: #OSError for Python3, RuntimeError for 2
    print ("Skipping {}".format(i))

如果你想摆脱这种尝试,就忽略那些无法捕捉到的信号

#!/usr/bin/env python
# https://stackoverflow.com/questions/2148888/python-trap-all-signals
import os
import sys
import time
import signal

SIGNALS_TO_NAMES_DICT = dict((getattr(signal, n), n) \
    for n in dir(signal) if n.startswith('SIG') and '_' not in n )


def receive_signal(signum, stack):
    if signum in [1,2,3,15]:
        print 'Caught signal %s (%s), exiting.' % (SIGNALS_TO_NAMES_DICT[signum], str(signum))
        sys.exit()
    else:
        print 'Caught signal %s (%s), ignoring.' % (SIGNALS_TO_NAMES_DICT[signum], str(signum))

def main():
    uncatchable = ['SIG_DFL','SIGSTOP','SIGKILL']
    for i in [x for x in dir(signal) if x.startswith("SIG")]:
        if not i in uncatchable:
            signum = getattr(signal,i)
            signal.signal(signum,receive_signal)
    print('My PID: %s' % os.getpid())
    while True:
        time.sleep(1)
main()

该代码在当前版本的python中不起作用。有许多变量以相同值的SIG开头。例如,SIGHUP和SIG_UNBLOCK都是1。我能想到的得到实际信号列表的唯一方法就是自己制作

from signal import *    
signals = {
        SIGABRT: 'SIGABRT',
        SIGALRM: 'SIGALRM',
        SIGBUS: 'SIGBUS',
        SIGCHLD: 'SIGCHLD',
        SIGCONT: 'SIGCONT',
        SIGFPE: 'SIGFPE',
        SIGHUP: 'SIGHUP',
        SIGILL: 'SIGILL',
        SIGINT: 'SIGINT',
        SIGPIPE: 'SIGPIPE',
        SIGPOLL: 'SIGPOLL',
        SIGPROF: 'SIGPROF',
        SIGQUIT: 'SIGQUIT',
        SIGSEGV: 'SIGSEGV',
        SIGSYS: 'SIGSYS',
        SIGTERM: 'SIGTERM',
        SIGTRAP: 'SIGTRAP',
        SIGTSTP: 'SIGTSTP',
        SIGTTIN: 'SIGTTIN',
        SIGTTOU: 'SIGTTOU',
        SIGURG: 'SIGURG',
        SIGUSR1: 'SIGUSR1',
        SIGUSR2: 'SIGUSR2',
        SIGVTALRM: 'SIGVTALRM',
        SIGXCPU: 'SIGXCPU',
        SIGXFSZ: 'SIGXFSZ',
        }

for num in signals:
    signal(num, h)

从Python3.5开始,信号常量为,支持更好的方法:

import signal

catchable_sigs = set(signal.Signals) - {signal.SIGKILL, signal.SIGSTOP}
for sig in catchable_sigs:
    signal.signal(sig, print)  # Substitute handler of choice for `print`

这里有一个2/3兼容的方法,它没有其他方法那么多的陷阱:

from itertools import count
import signal

def set_all_signal_signals(handler):
    """Set all signals to a particular handler."""
    for signalnum in count(1):
        try:
            signal.signal(signalnum, handler)
            print("set {}".format(signalnum))
        except (OSError, RuntimeError):
            # Invalid argument such as signals that can't be blocked
            pass
        except ValueError:
            # Signal out of range
            break

由于
signalnum
只是一个数字,因此在1上迭代以超出将信号设置为特定句柄的范围。

适用于Windows 10和Python 3.7:

import signal
import time

def sighandler(signal,frame):
    print("signal",sig,frame)
    return

catchable_sigs = set(signal.Signals)
for sig in catchable_sigs:
    try:
        signal.signal(sig, sighandler)
        print("Setting ",sig)
        print ("value {}".format(sig))
    except (ValueError, OSError, RuntimeError) as m:
        print("Skipping ",sig)
        print ("Value {}".format(sig))


# press some keys or issue kill
x = 0
while x < 5:
    time.sleep(4)
    x += 1
对于Python 3:

for sig in signal.Signals:
    try:
        signal.signal(sig, sighandler)
    except OSError:
        print('Skipping', sig)

在Python3.8中,我们有一个新函数
signal.valid\u signals()

导入信号
对于信号中的sig。有效的_信号()
打印(f“{sig:2d}”,sig)

我相信答案是“不”,某些信号甚至无法捕获(SIGKILL)。不客气。感谢您修复程序中的错误。:)这应该是RuntimeError,而不是RuntimeError。无法编辑,因为只有一个字符更改。您的列表理解将包括
SIG\u IGN
,这是一个操作,而不是信号。由于此动作“值”对应于
1
,这是
SIGHUP
的值,因此您将设置此信号两次。对于这个不重要的特定情况,此代码可能会因其他类似目的而崩溃。此答案不适用于Python 3,因为尝试设置不可阻止的信号,例如
SIGKILL
,现在抛出
OSError
,而不是
运行时错误
@BryceGuinta已修复。这应该适用于Pythons 2和Pythons 3。代码没有正确缩进,但我无法编辑它,因为不要让我做那么小的更改。所有的for都应该缩进一级,缩进少一级。请投票人留下评论好吗?这个答案有问题吗?这其实很有用。谢谢你能确认这在windows上是否有效吗?我不知道信号在windows上是如何工作的,但看起来核心功能是可用的:请注意,尽管信号功能只接受某些值,看起来signalsenum是用适合平台的信号构建的:所以我猜这种方法可以工作,可能需要一些小的调整。但是,我也不知道信号是如何工作的,甚至不知道它们在Windows上的含义,所以它可能根本不起作用。它的工作原理就像一个charmIt(查密特)一样,是不必要的。所有信号仍然以
SIG
开头,但您需要添加一个双重检查,以确保忽略
SIG
信号。
for sig in signal.Signals:
    try:
        signal.signal(sig, sighandler)
    except OSError:
        print('Skipping', sig)