iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 27
2
Software Development

Gosh!原來用 Go 寫一個 Unix Shell 這麼簡單系列 第 27

Day27-timeout 限時指令

前言

一轉眼就來到第 27 天、也是實作功能的最後一天了,在過去幾個禮拜 Gosh 一直嘗試做到 zsh 能做的事(雖然還差很多XD)

但今天要來點不一樣的,我要幫 Gosh 加上一個其他 Shell 都沒有的功能:限時指令,所以不要說都在學別人的功能,Gosh 也是有他的獨特之處的啊~~

功能 Demo

如果我希望 ping google.com 最多只跑三秒,那我就在最前面加上 timeout=3,變成 timeout=3 ping google.com,那他最多跑三秒之後就會自動停止

同樣,如果我希望 top 最多跑三秒,那我就可以下 timeout=3 top,那他三秒後就會被關掉,很實用吧~

做法

為了讓 Process 在時間到時被關掉,我們 需要在 Shell 裡面計時,時間到的時候就送一個 SIGINT 給正在跑的 Process,那 Process 就會在時間到時被殺掉

因為我們是用 Signal 來殺 Process,所以其實被執行的 Child Process 不會知道有限時,對 Child Process 來說他只是執行到一半突然被殺掉而已,所以 這個 timeout 機制可以適用於任何程式

實作

會用到的 function

  • strconv.Atoi(s string) (int, error)

    AtoiAscii to Int 的意思,可以用來 把字串轉成整數,譬如說 Atoi("3") 會把字串 "3" 轉成數字 3

  • time.Sleep(d Duration)

    time.Sleep 就跟他的名字一樣,是用來讓程式睡覺的,但他作用的範圍 只有 Goroutine(Thread) 而不是整個程式,譬如說 time.Sleep(time.Second) 可以讓目前的 Goroutine 暫停一秒再繼續跑下一行

func executeInput(input string) error {
    // ...
  
    // 預設是沒有限時的,timeout 為 0
    timeout := 0
    
    // 判斷使用者輸入的指令是不是 timeout= 開頭
    if strings.HasPrefix(args[0], "timeout=") {
        // 如果指令是 timeout= 開頭,那就需要限時
        // 譬如說 "timeout=3 ping google.com"
        // 這時 args[0] = "timeout=3"
        
        // 那就把 args[0] 的前八個字元(timeout=)去除掉得到 "3"
        // 再把字串 "3" 轉成整數,就可以成功把 timeout 設為 3
        timeout, _ = strconv.Atoi(args[0][8:])
        
        // 最後把指令中的 "timeout=3" 去掉
        // 因為他並不是指令的一部分
        // [timeout=3, ping, google.com] -> [ping, google.com]
        args = args[1:]
    }

    // ...

    cmd := exec.Command(args[0], args[1:]...)

    // ...

    // 判斷這個指令需不需要 timeout
    // timeout != 0 代表有限時
    if timeout != 0 {
        // 新開一個 goroutine 用來計時
        go func() {
            // 假如需要限時、timeout=3
            // 那就先讓 goroutine 睡個三秒
            time.Sleep(time.Duration(timeout) * time.Second)
            
            // 3 秒到了再發 SIGINT 給正在執行的 Process
            // 這樣 Process 就會在時間到時被結束掉
            cmd.Process.Signal(syscall.SIGINT)
        }()
    }

    // ...
}

小結

View commit on Github

今天自己實作了一個其他 Shell 沒有的功能,感覺心裡好踏實啊,相信各位讀者也有同感吧(是嗎??)

有問題的話歡迎在下面留言,沒問題的話明天要來細數一下有哪些功能是我沒做到的,雖然沒時間做了但我會說說他們大概要怎麼做,讓大家腦中有個概念


上一篇
Day26-& 背景執行
下一篇
Day28-那些來不及做的功能
系列文
Gosh!原來用 Go 寫一個 Unix Shell 這麼簡單30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言