Zac*_*c B 5 unix signals cross-platform go
假设我正在kill用 Go 实现该程序。我可以接受来自命令行的数字信号和 PID,并将它们发送出去,syscall.Kill没有任何问题。
但是,我不知道如何实现信号调度的“字符串”形式,例如kill -INT 12345。
真正的用例是一个较大程序的一部分,提示用户发送终止信号;不是 的替代品kill。
问题:
如何在运行时将有效信号名称转换为任何支持的平台上的信号号(或者至少无需编写要在编译时运行的每个平台代码)?
我尝试过的:
kill -l这不能以跨平台的方式工作(例如, Mac OSX 与现代 Linux 与旧版 Linux 上返回不同的信号列表)。使该解决方案普遍有效的唯一方法是为每个操作系统制作地图,这需要我了解每个操作系统的行为,并在它们添加新信号支持时保持最新状态。kill工具并从中捕获信号列表。这是不优雅且有点悖论的,并且还需要 a) 能够找到kill,b) 具有执行子进程的能力/权限,以及 c) 能够预测/解析kill二进制文件的输出。Signal的String方法。这仅返回包含信号编号的字符串,例如os.Signal(4).String() == "signal 4",这没有用。runtime.signame,它正是我想要的。go://linkname黑客会起作用,但我认为这种事情不受欢迎是有原因的。我没有尝试过的想法/事情:
syscall以某种方式反思和解析该成员SIG。有人告诉我这是不可能的,因为名字是被编译掉的;有没有可能,对于像信号名称这样基本的东西,在某些地方它们没有被编译掉?Commit d455e41于 2019 年 3 月添加了此功能,sys/unix.SignalNum()因此至少从 Go 1.13 起可用。更多详细信息,请参阅 GitHub 问题#28027。
从包的文档golang.org/x/sys/unix中:
func SignalNum(s string) syscall.SignalSignalNum 返回名为 s 的信号的 syscall.Signal,如果未找到具有此类名称的信号,则返回 0。信号名称应以“SIG”开头。
为了回答类似的问题,“如何列出所有可用信号的名称(在给定的类 Unix 平台上)”,我们可以使用反函数sys/unix.SignalName():
import "golang.org/x/sys/unix"
// See https://github.com/golang/go/issues/28027#issuecomment-427377759
// for why looping in range 0,255 is enough.
for i := syscall.Signal(0); i < syscall.Signal(255); i++ {
name := unix.SignalName(i)
// Signal numbers are not guaranteed to be contiguous.
if name != "" {
fmt.Println(name)
}
}
Run Code Online (Sandbox Code Playgroud)