Golang detect system interrupt

Viewed 40

I wrote an utility to batch delete files as followed

        stdinScanner := bufio.NewScanner(os.Stdin)
        fileScanner := bufio.NewScanner(inFile)
        for fileScanner.Scan() {
            target := strings.TrimSpace(fileScanner.Text())
            if len(target) > 0 {
                printUtf16("Delete %s?\n", target)
                stdinScanner.Scan()
                if len(stdinScanner.Text()) > 0 {
                    fmt.Println("Non empty return not allowed")
                    os.Exit(1)
                } else {
                    // TROUBLE: Had to sleep here or interrupt does not work
                    time.Sleep(100 * time.Millisecond)
                    e := os.Remove(target)
                    if e != nil {
                        panic(e)
                    }
                    printUtf16("%s deleted\n", target)
                }
            }
        }

I have an inFile that specifies a list of files I want to delete. For every file to delete, I prompt myself just to be sure. Only if I enter empty output would the program delete the file and proceed to the next file.

Now note the very ugly time.Sleep in this middle of the code. I have noticed that if I did not insert that time.Sleep the application behaves unexpectedly when I press ctrl+c. Seems like after ctrl+c is pressed stdinScanner.Scan() would return false and no error and stdinScanner.Text() would be empty just as I expected when an empty input is entered. The file that I was prompted for would be deleted before the application is interrupted and quits.

I have noticed that adding this time.Sleep allows the application more than sufficient time to exit and prevent the current file to be deleted. However I really dislike this solution. Just asking if there is a function I can call instead of the time.Sleep to check if the application is currently processing a keyboard interrupt and if so we don't delete the current file?

1 Answers

Thanks Volker and Cerise for the response The answer turns out is quite simple. Can't believe I overlooked it. We just need to check scanner's return and err before proceeding

scanResult := stdinScanner.Scan()
scanError := stdinScanner.Err()
if scanResult && scanError == nil {
    if len(stdinScanner.Text()) > 0 {
        fmt.Println("Non empty return not allowed")
        os.Exit(1)
    } else {
        deleteFunc(target)
    }
} else {
    errString := "None"
    if scanError != nil {
        errString = scanError.Error()
    }
    fmt.Printf("Scanner returns %t, err: %s\n", scanResult, errString)
    os.Exit(1)
}
Related