Go信号处理程序不处理终端窗口关闭事件。

huangapple go评论126阅读模式
英文:

Go signal handler doesn't handle terminal window closing

问题

我用Go语言编写了一个命令行工具。当通过终端调用该命令行工具时,我希望工具在调用cleanup()函数之前等待Ctrl+C中断(SIGINT),最后退出。

然而,除了处理SIGINT之外,我还希望该工具能处理用户简单关闭终端窗口的情况。如果窗口关闭,我希望调用相同的cleanup函数。以下是我尝试的示例代码。

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "syscall"
  6. "os/signal"
  7. "os/exec"
  8. "github.com/sirupsen/logrus"
  9. )
  10. func main() {
  11. // 解析命令行参数
  12. if len(os.Args) < 2 {
  13. logrus.Fatalf("缺少必需的参数")
  14. }
  15. arg := os.Args[1]
  16. logrus.Infof("使用参数运行:%s", arg)
  17. // 设置信号处理
  18. signals := make(chan os.Signal, 1)
  19. signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
  20. done := make(chan bool, 1)
  21. go func() {
  22. sig := <-signals
  23. fmt.Println("")
  24. fmt.Println("通过Ctrl+C请求断开连接", sig)
  25. done <- true
  26. }()
  27. logrus.Infof("按下Ctrl+C断开连接。")
  28. <-done
  29. cleanup()
  30. os.Exit(0)
  31. }
  32. func cleanup() {
  33. fmt.Println("执行清理任务...")
  34. touchFile := exec.Command("touch", "testfile.txt")
  35. _, err := touchFile.CombinedOutput()
  36. if err != nil {
  37. println(err)
  38. }
  39. }

这段代码可以处理用户通过Ctrl+C发送中断信号的情况,并调用cleanup函数,但是当用户简单关闭窗口时,cleanup函数不会被调用。我认为包含syscall.SIGHUP应该可以解决这个问题。请指导。

编辑:我在默认的MacOS终端中测试了这段代码,在关闭窗口时会调用cleanup函数,但在使用iTerm时不会调用。

英文:

I have written a cli tool in go. When the cli tool is invoked via the terminal, i want the tool to wait for a Ctrl+C interrupt(SIGINT) before calling a cleanup() function, before finally exiting.

however, as well as handling SIGINT, i also want the tool to handle cases where the terminal window is simply closed by the user. if its closed, i want the same cleanup function to be called. Here is a sample of what i tried.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;os&quot;
  5. &quot;syscall&quot;
  6. &quot;os/signal&quot;
  7. &quot;os/exec&quot;
  8. &quot;github.com/sirupsen/logrus&quot;
  9. )
  10. func main() {
  11. // Parse the command-line argument.
  12. if len(os.Args) &lt; 2 {
  13. logrus.Fatalf(&quot;Missing required argument&quot;)
  14. }
  15. arg := os.Args[1]
  16. logrus.Infof(&quot;Running with argument: %s&quot;, arg)
  17. // Set up signal handling.
  18. signals := make(chan os.Signal, 1)
  19. signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
  20. done := make(chan bool, 1)
  21. go func() {
  22. sig := &lt;-signals
  23. fmt.Println(&quot;&quot;)
  24. fmt.Println(&quot;Disconnection requested via Ctrl+C&quot;, sig)
  25. done &lt;- true
  26. }()
  27. logrus.Infof(&quot;Press Ctrl+C to disconnect.&quot;)
  28. &lt;-done
  29. cleanup()
  30. os.Exit(0)
  31. }
  32. func cleanup() {
  33. fmt.Println(&quot;Performing cleanup tasks...&quot;)
  34. touchFile := exec.Command(&quot;touch&quot;, &quot;testfile.txt&quot;,)
  35. _, err := touchFile.CombinedOutput()
  36. if err != nil {
  37. println(err)
  38. }
  39. }

This works for cases where the user sends an interrupt via Ctrl+C and the cleanup function is called, but the cleanup function is never called when the user simply just closes the window. I though the inclusion of syscall.SIGHUP would work for this. please advise.

Edit: i've tested this in the default MacOS terminal, and the cleanup function is called when closing the window, but not when using iTerm.

答案1

得分: 0

  1. package main
  2. import (
  3. redacted
  4. )
  5. func main() {
  6. // 解析命令行参数。
  7. if len(os.Args) < 2 {
  8. logrus.Fatalf("缺少必需的参数")
  9. }
  10. arg := os.Args[1]
  11. log.Infof("使用参数运行: %s", arg)
  12. // 设置信号处理。
  13. signals := make(chan os.Signal, 1)
  14. signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
  15. done := make(chan bool, 1)
  16. go func() {
  17. sig := <-signals
  18. fmt.Println("")
  19. fmt.Println("通过 Ctrl+C 请求断开连接", sig)
  20. done <- true
  21. }()
  22. log.Infof("按下 Ctrl+C 断开连接。")
  23. <-done
  24. cleanup()
  25. os.Exit(0)
  26. }
  27. func cleanup() {
  28. fmt.Println("执行清理任务...")
  29. touchFile := exec.Command("touch", "testfile.txt")
  30. _, err := touchFile.CombinedOutput()
  31. if err != nil {
  32. println(err)
  33. }
  34. }

现在在 iTerm 中添加了 SIGKILL 的功能。

英文:
  1. package main
  2. import (
  3. redacted
  4. )
  5. func main() {
  6. // Parse the command-line argument.
  7. if len(os.Args) &lt; 2 {
  8. logrus.Fatalf(&quot;Missing required argument&quot;)
  9. }
  10. arg := os.Args[1]
  11. log.Infof(&quot;Running with argument: %s&quot;, arg)
  12. // Set up signal handling.
  13. signals := make(chan os.Signal, 1)
  14. signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
  15. done := make(chan bool, 1)
  16. go func() {
  17. sig := &lt;-signals
  18. fmt.Println(&quot;&quot;)
  19. fmt.Println(&quot;Disconnection requested via Ctrl+C&quot;, sig)
  20. done &lt;- true
  21. }()
  22. log.Infof(&quot;Press Ctrl+C to disconnect.&quot;)
  23. &lt;-done
  24. cleanup()
  25. os.Exit(0)
  26. }
  27. func cleanup() {
  28. fmt.Println(&quot;Performing cleanup tasks...&quot;)
  29. touchFile := exec.Command(&quot;touch&quot;, &quot;testfile.txt&quot;,)
  30. _, err := touchFile.CombinedOutput()
  31. if err != nil {
  32. println(err)
  33. }
  34. }

The addition of SIGKILL works now for iTerm.

huangapple
  • 本文由 发表于 2022年12月24日 02:00:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/74902679.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定