Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Bagaimana untuk membaca dan memformat aliran teks yang diterima melalui paip bash?

Bagaimana untuk membaca dan memformat aliran teks yang diterima melalui paip bash?

WBOY
WBOYke hadapan
2024-02-10 23:30:09462semak imbas

如何读取和格式化通过 bash 管道接收的文本流?

Dalam kerja harian kita, kita selalunya perlu memproses data teks melalui alatan baris arahan. Dalam sistem Linux, paip bash (paip) adalah alat yang sangat berkuasa yang boleh menggunakan output satu arahan sebagai input arahan lain. Tetapi apabila kami menerima aliran teks yang besar melalui paip, bagaimanakah kami membaca dan memformat data ini dengan cekap? Artikel ini akan memperkenalkan anda kepada beberapa petua dan kaedah praktikal untuk membantu anda mengendalikan strim teks yang diterima melalui paip bash dengan lebih baik. Sama ada anda seorang pemula atau pembangun yang berpengalaman, artikel ini akan membawa anda sedikit inspirasi dan bantuan.

Kandungan soalan

Pada masa ini, saya menggunakan yang berikut untuk memformat data dalam skrip npm.

npm run startwin | while ifs= read -r line; do printf '%b\n' "$line"; done | less

Ia berfungsi tetapi rakan sekerja saya tidak menggunakan linux. Jadi, saya ingin melaksanakan while ifs= read -r line;执行 printf '%bn' "$line";在go中完成 dan menggunakan binari dalam perancangan.

npm run startwin | magical-go-formater

Apa yang saya cuba

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)
    }
}

Pada masa ini, program menyenyapkan semua output strim teks.

Penyelesaian

Anda ingin menggunakan bufio.scanner untuk bacaan jenis ekor. IMHO cek yang anda buat pada os.stdin tidak diperlukan, tetapi ymmv.

Lihat jawapan ini sebagai contoh. ioutil.readall() (现已弃用,只需使用 io.readall() )读取错误/eof,但它不是循环输入 - 这就是您需要 bufio.scanner.scan() sebab. p>

Juga - %b 将转换文本中的任何转义序列 - 例如传递的行中的任何 n semua akan dipaparkan sebagai baris baharu - adakah anda memerlukannya? b/c go tidak mempunyai penentu format yang setara, afaik.

Edit

Jadi saya fikir, anda berdasarkan kod sumber perpustakaan standard readall() 的方法将会/可能会起作用......最终。我猜您期望的行为与 bufio.scanner 类似 - 接收进程在写入字节时处理字节(这实际上是一个轮询操作 - 请参阅 scan() untuk melihat butiran yang kotor) .

Tetapi dengan versi instrumen readall() 会缓冲读取的所有内容,并且直到最终出现错误或 eof 才会返回。我破解了 readall() (iaitu salinan tepat kod sumber perpustakaan standard, dengan hanya sedikit output instrumentasi tambahan), anda boleh melihat bahawa ia dibaca semasa bait sedang ditulis, tetapi ia tidak lengkap selepas proses penulisan Ia tidak mengembalikan dan menghasilkan kandungan sebelum ini, pada ketika itu ia menutup hujung paip (pemegang fail terbukanya), dengan itu menghasilkan 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
        }
    }
}

Saya baru sahaja menulis skrip murah untuk menjana input, mensimulasikan beberapa perkara yang berjalan lama dan hanya menulis secara berkala, saya bayangkan bagaimana npm akan berkelakuan dalam kes anda:

#!/bin/sh

for x in 1 2 3 4 5 6 7 8 9 10
do
  cat ./main.go
  sleep 10
done

BTW, saya dapati membaca kod perpustakaan standard sebenar sangat membantu... atau sekurang-kurangnya menarik dalam kes seperti ini.

Atas ialah kandungan terperinci Bagaimana untuk membaca dan memformat aliran teks yang diterima melalui paip bash?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam