在我們的日常工作中,經常需要通過命令行工具來處理文本數據。而在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
登錄后復制
順便說一句,我發現閱讀實際的標準庫代碼確實很有幫助……或者至少在這樣的情況下很有趣。