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

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

Go signal handler doesn't handle terminal window closing

问题

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

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

package main

import (
	"fmt"
	"os"
	"syscall"
	"os/signal"
	"os/exec"
	"github.com/sirupsen/logrus"
)

func main() {
	// 解析命令行参数
	if len(os.Args) < 2 {
		logrus.Fatalf("缺少必需的参数")
	}
	arg := os.Args[1]

	logrus.Infof("使用参数运行:%s", arg)

	// 设置信号处理
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)

	done := make(chan bool, 1)
	go func() {
		sig := <-signals
		fmt.Println("")
		fmt.Println("通过Ctrl+C请求断开连接", sig)
		done <- true
	}()

	logrus.Infof("按下Ctrl+C断开连接。")
	<-done

	cleanup()

	os.Exit(0)
}

func cleanup() {
	fmt.Println("执行清理任务...")
	touchFile := exec.Command("touch", "testfile.txt")
	_, err := touchFile.CombinedOutput()

	if err != nil {
		println(err)
	}
}

这段代码可以处理用户通过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.

package main

import (
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;syscall&quot;
	&quot;os/signal&quot;
	&quot;os/exec&quot;
	&quot;github.com/sirupsen/logrus&quot;
)

func main() {
	// Parse the command-line argument.
	if len(os.Args) &lt; 2 {
		logrus.Fatalf(&quot;Missing required argument&quot;)
	}
	arg := os.Args[1]

	logrus.Infof(&quot;Running with argument: %s&quot;, arg)

	// Set up signal handling.
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)

	done := make(chan bool, 1)
	go func() {
		sig := &lt;-signals
		fmt.Println(&quot;&quot;)
		fmt.Println(&quot;Disconnection requested via Ctrl+C&quot;, sig)
		done &lt;- true
	}()

	logrus.Infof(&quot;Press Ctrl+C to disconnect.&quot;)
	&lt;-done

	cleanup()

	os.Exit(0)
}

func cleanup() {
	fmt.Println(&quot;Performing cleanup tasks...&quot;)
	touchFile := exec.Command(&quot;touch&quot;, &quot;testfile.txt&quot;,)
	_, err := touchFile.CombinedOutput()

	if err != nil {
		println(err)
	}
}

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

package main

import (
	redacted
)

func main() {
	// 解析命令行参数。
	if len(os.Args) < 2 {
		logrus.Fatalf("缺少必需的参数")
	}
	arg := os.Args[1]

	log.Infof("使用参数运行: %s", arg)

	// 设置信号处理。
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)

	done := make(chan bool, 1)
	go func() {
		sig := <-signals
		fmt.Println("")
		fmt.Println("通过 Ctrl+C 请求断开连接", sig)
		done <- true
	}()

	log.Infof("按下 Ctrl+C 断开连接。")
	<-done

	cleanup()

	os.Exit(0)
}

func cleanup() {
	fmt.Println("执行清理任务...")
	touchFile := exec.Command("touch", "testfile.txt")
	_, err := touchFile.CombinedOutput()

	if err != nil {
		println(err)
	}
}

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

英文:
package main

import (
redacted
)

func main() {
	// Parse the command-line argument.
	if len(os.Args) &lt; 2 {
		logrus.Fatalf(&quot;Missing required argument&quot;)
	}
	arg := os.Args[1]

	log.Infof(&quot;Running with argument: %s&quot;, arg)

	// Set up signal handling.
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)

	done := make(chan bool, 1)
	go func() {
		sig := &lt;-signals
		fmt.Println(&quot;&quot;)
		fmt.Println(&quot;Disconnection requested via Ctrl+C&quot;, sig)
		done &lt;- true
	}()

	log.Infof(&quot;Press Ctrl+C to disconnect.&quot;)
	&lt;-done

	cleanup()

	os.Exit(0)
}

func cleanup() {
	fmt.Println(&quot;Performing cleanup tasks...&quot;)
	touchFile := exec.Command(&quot;touch&quot;, &quot;testfile.txt&quot;,)
	_, err := touchFile.CombinedOutput()

	if err != nil {
		println(err)
	}
}

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:

确定