学习Go语言,试图弄清楚exec包。有哪些方法可以改进我的代码?

huangapple go评论74阅读模式
英文:

Learning go, trying to figure out the exec package. In what ways can I improve my code?

问题

写了一个简单的程序,调用了"ls"命令,然后通过正则表达式过滤每一行以"s"结尾的文件。ls命令仅用于学习exec包的目的。如何改进下面的代码以使其更正确/简洁/符合Go语言的风格?

package main

import (
    "bufio"
    "fmt"
    "os/exec"
    "regexp"
)

func main() {

    cmd := exec.Command("ls")
    stdout, _ := cmd.StdoutPipe()
    s := bufio.NewReader(stdout)
    cmd.Start()

    go cmd.Wait()

    for {
        l, _, err := s.ReadLine()
        if err != nil {
            break
        }

        if m, err := regexp.Match(".*s$", l); m && err == nil {
            fmt.Println(string(l))
        }
    }
}
英文:

Wrote a simple program that calls "ls", then passes each line through regexp filtering for files that end in an "s". ls is used only for the purposes of learning the exec package. How can I improve the code below to be more correct/succinct/go-ish?

package main

import (
	"bufio"
	"fmt"
	"os/exec"
	"regexp"
)

func main() {

	cmd := exec.Command("ls")
	stdout, _ := cmd.StdoutPipe()
	s := bufio.NewReader(stdout)
	cmd.Start()

	go cmd.Wait()

	for {
		l, _, err := s.ReadLine()
		if err != nil {
			break
		}

		if m, err := regexp.Match(".*s$", l); m && err == nil {
			fmt.Println(string(l))
		}
	}
}

答案1

得分: 3

标准文档中的Cmd.Output示例非常简洁。它没有进行任何文本处理,但展示了如何执行命令并通过单个函数调用获取输出。

以下是将该示例与您的示例结合的方法:

package main

import (
    "bytes"
    "fmt"
    "log"
    "os/exec"
    "regexp"
)

func main() {
    out, err := exec.Command("ls").Output()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Print(string(bytes.Join(regexp.MustCompile(".*s\n").FindAll(out, -1), nil)))
}

如果目标是对该包进行广泛概述,可以尝试使用多个函数和方法来了解它们的不同功能。尝试使用命令参数进行实验。尝试使用Cmd结构体的不同字段。尽量不要分散注意力到其他包(如regexp),只寻找练习包功能的最简单示例。

当然,如果您看到如何在实际应用程序中使用exec功能,可以尝试一下。这样您将更深入地了解该功能。

英文:

The Cmd.Output example in the standard documentation is pretty succinct. It doesn't do any text processing, but it shows how to execute a command and get the output with a single function call.

Here's a way to combine that example with yours,

package main

import (
    "bytes"
    "fmt"
    "log"
    "os/exec"
    "regexp"
)

func main() {
    out, err := exec.Command("ls").Output()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Print(string(bytes.Join(regexp.MustCompile(".*s\n").FindAll(out, -1), nil)))
}

If the goal is to get a broad overview of the package, experiment with a number of the functions and methods to learn their different capabilities. Experiment with command arguments. Experiment with the different fields of the Cmd struct. Try not to get too distracted with other packages like regexp, just look for the simplest examples that exercise a package feature.

Of course if you see how you might use an exec feature in a real application, try it. You'll learn that one feature in more depth.

答案2

得分: 2

添加错误检查并停止使用正则表达式来处理这种类型的示例。

对于任何大于缓冲区大小的输入数据,ReadLine将不可避免地在某个点返回isPrefix设置为true。ReadString('\n')可以实现你想要的功能 - 无论是否适合缓冲区,都会读取到行尾,并扩展输出字符串。这也意味着你可能会得到一个任意长的字符串。对于ReadLine()来说,好处是它会自动去掉行尾的"\n"或"\r\n",所以当使用ReadString()时,我们需要自己处理这个问题。

package main

import (
    "bufio"
    "fmt"
    "os/exec"
    "io"
)

func main() {
    var err error
    var out io.Reader

    // 创建一个命令对象
    cmd := exec.Command("ls")

    // 获取一个管道来接收命令的标准输出
    out, err = cmd.StdoutPipe(); if err != nil {
        panic(err)
    }

    // 启动子进程
    err = cmd.Start(); if err != nil {
        panic(err)
    }

    // bufio.Reader允许我们读取所有字节直到换行符
    s := bufio.NewReader(out)
    for {
        var line string
        line, err = s.ReadString('\n')
        if err == io.EOF && len(line) == 0 {
            // 文件末尾,没有部分行
            break
        }
        if err == io.EOF {
            err := fmt.Errorf("最后一行没有结束符: %q", line)
            panic(err)
        }
        if err != nil {
            panic(err)
        }
        line = line[:len(line)-1]       // 去掉'\n'
        if line[len(line)-1] == '\r' {
            line = line[:len(line)-1]   // 去掉'\r'
        }
        if line[len(line)-1] == 's' {   // 最后检查以's'结尾的行
            fmt.Println(line)
        }
    }

    // 等待命令的结果;也关闭我们的管道的一端
    err = cmd.Wait()
    if err != nil {
        panic(err)
    }
}
英文:

Add error checking and stop using regexp for this kind of example.

For any input data larger than the buffer size, ReadLine will inevitably return with isPrefix set to true at some point. ReadString('\n') does what you want - reading until end of line regardless of whether it fits in the buffer, extending the output string as is goes. That also means you could end up with an arbitrarily long string. On the plus side for ReadLine(), it does drop the "\n" or "\r\n" from the end of the line for you, so when using ReadString(), we have to do that ourselves.

package main

import (
    "bufio"
    "fmt"
    "os/exec"
    "io"
)

func main() {
    var err error
    var out io.Reader

    // Create a command object
    cmd := exec.Command("ls")

    // Obtain a pipe to receive the stdout of the command
    out, err = cmd.StdoutPipe(); if err != nil {
        panic(err)
    }

    // Start the child process
    err = cmd.Start(); if err != nil {
        panic(err)
    }

    // bufio.Reader allows us to read all bytes until newline
    s := bufio.NewReader(out)
    for {
        var line string
        line, err = s.ReadString('\n')
        if err == io.EOF && len(line) == 0 {
            // Good end of file with no partial line
            break
        }
        if err == io.EOF {
            err := fmt.Errorf("Last line not terminated: %q", line)
            panic(err)
        }
        if err != nil {
            panic(err)
        }
        line = line[:len(line)-1]       // drop the '\n'
        if line[len(line)-1] == '\r' {
            line = line[:len(line)-1]   // drop the '\r'
        }
        if line[len(line)-1] == 's' {   // Finally check for lines ending in 's'
            fmt.Println(line)
        }
    }

    // Wait for the result of the command; also closes our end of the pipe
    err = cmd.Wait()
    if err != nil {
        panic(err)
    }
}

答案3

得分: 0

例如,

package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os/exec"
)

func main() {
	cmd := exec.Command("ls")
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println(err)
		return
	}
	ls := bufio.NewReader(stdout)
	err = cmd.Start()
	if err != nil {
		fmt.Println(err)
		return
	}
	for {
		line, isPrefix, err := ls.ReadLine()
		if isPrefix {
			fmt.Println(errors.New("isPrefix: true"))
			return
		}
		if err != nil {
			if err != io.EOF {
				fmt.Println(err)
				return
			}
			break
		}
		fmt.Println(string(line))
	}
	err = cmd.Wait()
	if err != nil {
		fmt.Println(err)
		return
	}
}

输出(取决于您的目录内容):

bench.go
temp.go
英文:

For example,

package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os/exec"
)

func main() {
	cmd := exec.Command("ls")
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println(err)
		return
	}
	ls := bufio.NewReader(stdout)
	err = cmd.Start()
	if err != nil {
		fmt.Println(err)
		return
	}
	for {
		line, isPrefix, err := ls.ReadLine()
		if isPrefix {
			fmt.Println(errors.New("isPrefix: true"))
			return
		}
		if err != nil {
			if err != io.EOF {
				fmt.Println(err)
				return
			}
			break
		}
		fmt.Println(string(line))
	}
	err = cmd.Wait()
	if err != nil {
		fmt.Println(err)
		return
	}
}

Output (depends on your directory contents):

bench.go
temp.go

huangapple
  • 本文由 发表于 2012年6月5日 12:00:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/10891381.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定