在我們的日常工作中,經常需要通過命令行工具來處理文本數據。而在Linux系統中,bash管道(pipe)是一個非常強大的工具,可以將一個命令的輸出作為另一個命令的輸入。但是,當我們通過管道接收到一大段文本流時,如何有效地讀取和格式化這些數據呢?本文將為大家介紹一些實用的技巧和方法,幫助你更好地處理通過bash管道接收的文本流。無論你是初學者還是有一定經驗的開發者,本文都將給你帶來一些啟發和幫助。
問題內容
目前,我正在使用以下內容來格式化 npm 腳本中的數據。
npm run startwin | while ifs= read -r line; do printf '%b\n' "$line"; done | less
登錄后復制
它可以工作,但我的同事不使用 linux。所以,我想實現 while ifs= read -r line;執行 printf '%b\n' "$line";在go中完成,并在管道中使用二進制文件。
npm run startwin | magical-go-formater
登錄后復制
我嘗試過的
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
fi, _ := os.Stdin.Stat() // get the FileInfo struct
if (fi.Mode() & os.ModeCharDevice) == 0 {
bytes, _ := ioutil.ReadAll(os.Stdin)
str := string(bytes)
arr := strings.Fields(str)
for _, v := range arr {
fmt.Println(v)
}
}
登錄后復制
目前,程序會靜默文本流的所有輸出。
解決方法
您想使用 bufio.scanner 進行尾部類型讀取。恕我直言,您在 os.stdin 上進行的檢查是不必要的,但是 ymmv。
請參閱此答案了解示例。 ioutil.readall() (現已棄用,只需使用 io.readall() )讀取錯誤/eof,但它不是循環輸入 – 這就是您需要 bufio.scanner.scan() 的原因。
此外 – %b 將轉換文本中的任何轉義序列 – 例如傳遞的行中的任何 \n 都將呈現為換行符 – 您需要嗎? b/c go 沒有等效的格式說明符,afaik。
編輯
所以我認為,您基于 readall() 的方法將會/可能會起作用……最終。我猜您期望的行為與 bufio.scanner 類似 – 接收進程在寫入字節時處理字節(這實際上是一個輪詢操作 – 請參閱 scan() 的標準庫源代碼以查看骯臟的細節) .
但是 readall() 會緩沖讀取的所有內容,并且直到最終出現錯誤或 eof 才會返回。我破解了 readall() 的檢測版本(這是標準庫源代碼的精確副本,只有一點點額外的檢測輸出),您可以看到它在寫入字節時正在讀取,但它只是沒有在寫入過程完成之前不會返回并產生內容,此時它會關閉管道的末端(其打開的文件句柄),從而生成 eof:
package main
import (
"fmt"
"io"
"os"
"time"
)
func main() {
// os.stdin.setreaddeadline(time.now().add(2 * time.second))
b, err := readall(os.stdin)
if err != nil {
fmt.println("error: ", err.error())
}
str := string(b)
fmt.println(str)
}
func readall(r io.reader) ([]byte, error) {
b := make([]byte, 0, 512)
i := 0
for {
if len(b) == cap(b) {
// add more capacity (let append pick how much).
b = append(b, 0)[:len(b)]
}
n, err := r.read(b[len(b):cap(b)])
//fmt.fprintf(os.stderr, "read %d - received: \n%s\n", i, string(b[len(b):cap(b)]))
fmt.fprintf(os.stderr, "%s read %d - received %d bytes\n", time.now(), i, n)
i++
b = b[:len(b)+n]
if err != nil {
if err == io.eof {
fmt.fprintln(os.stderr, "received eof")
err = nil
}
return b, err
}
}
}
登錄后復制
我剛剛編寫了一個廉價的腳本來生成輸入,模擬一些長時間運行的東西并且僅定期編寫,我想象 npm 在你的情況下的表現如何:
#!/bin/sh for x in 1 2 3 4 5 6 7 8 9 10 do cat ./main.go sleep 10 done
登錄后復制
順便說一句,我發現閱讀實際的標準庫代碼確實很有幫助……或者至少在這樣的情況下很有趣。






