Maison >développement back-end >Golang >Comment lire et formater un flux de texte reçu via un tube bash ?

Comment lire et formater un flux de texte reçu via un tube bash ?

WBOY
WBOYavant
2024-02-10 23:30:09538parcourir

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

Dans notre travail quotidien, nous devons souvent traiter des données textuelles via des outils de ligne de commande. Dans les systèmes Linux, bash pipe (pipe) est un outil très puissant qui peut utiliser la sortie d'une commande comme entrée d'une autre commande. Mais lorsque nous recevons un flux de texte volumineux via un canal, comment pouvons-nous lire et formater efficacement ces données ? Cet article vous présentera quelques conseils et méthodes pratiques pour vous aider à mieux gérer les flux de texte reçus via les tuyaux bash. Que vous soyez débutant ou développeur expérimenté, cet article vous apportera inspiration et aide.

Contenu de la question

Actuellement, j'utilise ce qui suit pour formater les données dans un script npm.

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

Cela fonctionne mais mon collègue n'utilise pas Linux. Donc, je veux implémenter while ifs= read -r line;执行 printf '%bn' "$line";在go中完成 et utiliser le binaire dans le pipeline.

npm run startwin | magical-go-formater

Ce que j'ai essayé

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

Actuellement, le programme coupe toutes les sorties du flux de texte.

Solution de contournement

Vous souhaitez utiliser bufio.scanner pour la lecture du type de queue. À mon humble avis, le chèque que vous avez fait sur os.stdin est inutile, mais ymmv.

Voir cette réponse pour un exemple. ioutil.readall() (现已弃用,只需使用 io.readall() )读取错误/eof,但它不是循环输入 - 这就是您需要 bufio.scanner.scan() raisons. p>

Aussi - %b 将转换文本中的任何转义序列 - 例如传递的行中的任何 n seront tous rendus sous forme de nouvelles lignes - en avez-vous besoin ? b/c go n'a pas de spécificateur de format équivalent, autant que je sache.

Modifier

Donc je pense que vous avez basé le code source de la bibliothèque standard de readall() 的方法将会/可能会起作用......最终。我猜您期望的行为与 bufio.scanner 类似 - 接收进程在写入字节时处理字节(这实际上是一个轮询操作 - 请参阅 scan() pour voir les détails sales) .

Mais avec la version instrumentée de readall() 会缓冲读取的所有内容,并且直到最终出现错误或 eof 才会返回。我破解了 readall() (qui est une copie exacte du code source de la bibliothèque standard, avec juste une petite sortie d'instrumentation supplémentaire), vous pouvez voir qu'elle lit au fur et à mesure que les octets sont écrits, mais elle ne se termine tout simplement pas après le processus d'écriture, il ne renvoie pas et ne produit pas de contenu avant, auquel cas il ferme l'extrémité du tuyau (son descripteur de fichier ouvert), produisant ainsi un 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
        }
    }
}

Je viens d'écrire un script bon marché pour générer des entrées, simuler des tâches de longue durée et n'écrire que périodiquement, j'imagine comment npm se comporterait dans votre cas :

#!/bin/sh

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

BTW, je trouve que la lecture du code de la bibliothèque standard est vraiment utile... ou du moins intéressante dans des cas comme celui-ci.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer