昨天已經成功讓 Shell 接到 Signal 而且不被打死,今天要來看看怎麼把 Signal 送給正在執行的 Process
因為使用者按下 <Ctrl>-C
時不見得有程式正在執行,像昨天的範例就是在等待使用者輸入的情況下收到 SIGINT
所以根據收到 SIGINT 的當下有沒有程式在執行,可以分成兩種情況:
如果收到 SIGINT 時 有 Process 正在執行 ,那就把 SIGINT 轉給那個 Process 讓他停止,就像是前天在 zsh 中把正在執行的 ping google.com
停掉
如果收到 SIGINT 的當下 沒有程式在跑 ,那就直接忽略 SIGINT,並且顯示出一個新的 prompt(如下圖 zsh 的做法)
(Process) Signal(sig Signal)
Process
型別的變數有一個 function 叫做 Signal
可以用,他是用來發送一個 Signal 給該 Process
為了要判斷收到 Signal 的當下有沒有指令正在跑,必須在執行指令之前把指令變數紀錄起來
// 宣告一個變數 currentCmd 來記錄目前正在執行的指令
var currentCmd *exec.Cmd
func executeInput(input string) error {
// ...
cmd := exec.Command(args[0], args[1:]...)
cmd.Stdin = inputStream
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
/* 以上是之前寫的程式碼 */
// 在執行之前把要執行的指令記起來
// 表示目前正在執行這個指令
currentCmd = cmd
err := cmd.Run()
// 執行結束之後就把 currentCmd 設為 nil
// 表示目前沒有在執行指令
currentCmd = nil
return err
}
在 handleSignals 裡面判斷目前有沒有指令在執行,並執行相對應的動作
func main(){
// ...
handleSignals := func() {
for {
sig := <-signalCh
// 判斷收到 Signal 時 currentCmd 是不是 nil
// 也就是當下有沒有指令在執行
if currentCmd != nil {
// 如果收到 Signal 時有指令在跑
// 那就把 Signal 轉送給那個 Process
currentCmd.Process.Signal(sig)
} else {
// 如果收到 Signal 時沒有指令在跑
// 那就顯示一個新的 prompt
fmt.Println()
showPrompt()
}
}
}
go handleSignals()
}
<Ctrl>-C
停掉正在執行的 ping google.com
今天終於把轉發 Signal 的任務完成了~雖然這邊只示範轉發 SIGINT,但其他 signal 也是類似的做法,有興趣的話可以自己做做看~