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

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

管道是什麼

但凡在類 Unix 系統上敲過命令的人,大多使用過管道功能. 所謂管道,就是將A程序的標準輸出做爲B程序的標準輸入。而在類 Unix 系統只須要使用 | 符號,鏈接 A 和 B 程序便可, 即 A | B。經過屢次管道鏈接,就能夠實現很是強大的功能。因此在類 Unix 系統上開發命令行程序有個著名的原則: KISS,即 Keep It Simple Stupid。github

畫了張簡單的圖:segmentfault

圖片描述

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)輸入。該方式判斷有一個注意點:spa

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

因此使用這種方式須要瞭解不一樣條件設置的用途,請結合實際開發需求。除了這個方式之外,還有另外更加簡單的實現方法:命令行

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

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

相關文章
相關標籤/搜索