Introduction
In this tutorial, we will answer the question “Is it possible to
capture a Ctrl+C signal (SIGINT) and run a cleanup function, in a
“defer” fashion” in Golang.
The answer is yes, with the help of the built-in packageos/signal, we can handle incoming signals. A way for processes to communicate is through signals. When a process receives a signal, it interrupts itself in order to run a signal handler. The type of signal received typically determines how the software operates.
SIGINT is the signal sent when we press Ctrl+C. The default action is
to terminate the process. However, some programs override this action
and handle it differently**.** One common example is
thebash
interpreter. When we press Ctrl+C it doesn’t quit, instead, it prints
a new and empty prompt line.
On Windows Control-C or (Control-Break) normally cause the program to
exit. If Notify is called for os.Interrupt, Ctrl+C or BREAK will cause
os.Interrupt to be sent on the channel, and the program will not exit.
If Reset is called, or Stop is called on all channels passed to Notify,
then the default behavior will be restored.
Example 1: Capture a Ctrl+C trap signal using os/signal package
In this example, we will use the Notify() function to capture the
os.Interrupt signal (Ctrl+C).
func Notify(c chan<- os.Signal, sig ...os.Signal): Notify causes
package signal to relay incoming signals to c. If no signals are
provided, all incoming signals will be relayed to c. Otherwise, just the
provided signals will. Package signal will not block sending to c: the
caller must ensure that c has sufficient buffer space to keep up with
the expected signal rate. For a channel used for notification of just
one signal value, a buffer of size 1 is sufficient.
package main
import (
"fmt"
"os"
"os/signal"
"time"
)
func main() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
fmt.Println(sig)
}
}()
temp := 0
for temp < 10 {
fmt.Println("sleeping...")
time.Sleep(2 * time.Second)
temp += 1
}
}
Output:
Firstly, I created a
goroutine to handle
the signals from keyboard. Whenever the
os.I<code class="language-go">nterrupt is captured, this goroutine
will print out a message to the console. While in the main goroutine, we
have a for loop to keep it running.
Example 2: Another example to capture a Ctrl+C signal
We can apply another technic with channel to catch the interrupt signal and do some operations before exiting:
package main
import (
"fmt"
"os"
"os/signal"
"time"
)
func main() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
fmt.Println("Program killed!")
cleanup()
os.Exit(1)
}()
for {
fmt.Println("sleeping...")
time.Sleep(2 * time.Second)
}
}
func cleanup() {
fmt.Println("This is the clean up function")
}
Output:
sleeping...
Program killed!
This is the clean up function
exit status 1
To slightly expand on the previous answers, syscall can be used to intercept SIGTERM, the standard signal sent by the kill command. Instead of os.Interrupt, use SIGTERM. Be aware that the syscall interface depends on the OS and may not always function (e.g. on windows). But catching both works well:
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
Example 3: Block the main goroutine until SIGINT signal
In this example, we will create 2 channel, 1 for handle the signals and 1 for block the main goroutine. When we run this program it will block waiting for a signal. By typing ctrl-C (which the terminal shows as ^C) we can send a SIGINT signal, causing the program to print interrupt and then exit.
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
c := make(chan os.Signal, 1)
check := make(chan bool, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-c
fmt.Println()
fmt.Println(sig)
check <- true
fmt.Println("This is the clean up message")
}()
fmt.Println("waiting for Ctrl+C signal")
<-check
fmt.Println("Done!!")
}
Output:
Summary
In some cases, we need to do extra work if users press Ctrl+Cto terminate the program. This post shows how to capture Ctrl+C event and run the handler inGo. We can easily use the built-in package os/signal to catch and handle this signal.

![GO capture ctrl+c signal & run cleanup function? [SOLVED]](/go-capture-ctrl-c/golang-capture-ctrlc.jpg)
