一分鐘學會在 Go 程序中實現管道 pipeline 功能

乘着打盹的時間看了一眼前兩天寫的日期轉換的開源工具: ts。發現管道 pipeline 的功能點可以放大一下, 就此記錄一下以備將來只需。

管道是什麼

但凡在類 Unix 系統上敲過命令的人,大多使用過管道功能. 所謂管道,就是將A程序的標準輸出作爲B程序的標準輸入。而在類 Unix 系統只需要使用 | 符號,連接 A 和 B 程序即可, 即 A | B。通過多次管道連接,就可以實現非常強大的功能。所以在類 Unix 系統上開發命令行程序有個著名的原則: KISS,即 Keep It Simple Stupid。

畫了張簡單的圖:

圖片描述

Go 程序

在 Go 程序中實現管道功能及其簡單,直接上碼:

    //先取程序的標準輸入屬性信息
    info, err := os.Stdin.Stat()
    if err != nil {
        return errors.Annotate(err, "stdin stat failed")
    }

    // 判斷標準輸入設備屬性 os.ModeCharDevice 是否設置
    // 同時判斷是否有數據輸入 
    if (info.Mode()&os.ModeCharDevice) == os.ModeCharDevice &&
        info.Size() > 0 {
        bytes, err := ioutil.ReadAll(os.Stdin)
        if err != nil {
            return errors.Annotate(err, "stdin read failed")
        }
        //TODO...
    }

屬性 os.ModeCharDevice 的意思是標準輸入的設備類型是Unix字節流設備(Unix character device)即終端(terminal)輸入。該方式判斷有一個注意點:

需要判斷 info.Size(), 即標準輸入是有數據輸入的。如果終端沒有輸入的話,程序會在 ioutil.ReadAll 處阻塞。

所以使用這種方式需要了解不同條件設置的用途,請結合實際開發需求。除了這個方式以外,還有另外更加簡單的實現方法:

    // 直接判斷 標準輸入屬性是否設置 os.ModeNamedPipe 即可
    if (info.Mode()&os.ModeNamedPipe) == os.ModeNamedPipe {
        //TODO...
    }

標準輸入只有在存在輸入的時候,纔會設置os.ModeNamedPipe屬性。相比較第一種方式,這種方式代碼更加簡單。只是命名管道(NamedPipe)又來了一個新概念,增加了理解的難度。引入一個 Linux 命令mkfifo,這個命令就是創建命名管道用的。至於爲什麼這裏程序的os.Stdin屬性會是os.ModeNamedPipe,我這先偷個懶了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章