使用 <(..) 参数执行

标签 go exec

我正在尝试使用 exec 获得等价物

diff <(echo "foo") <(echo "bar")

产生:

1c1
< foo
---
> bar

但是当我尝试时:

cmd := exec.Command("diff", "<(echo foo)", "<(echo bar)")

输出是:

exit status 2
diff: <(echo foo): No such file or directory
diff: <(echo bar): No such file or directory

最佳答案

FUZxxl 的回答很简单,但需要使用 bash。 Bash 并不是真正的跨平台,作为一个解释器,它对代码注入(inject)是开放的。我将首先描述一种使用 Go 复制它的方法,然后描述 git 使用的答案。

<(echo foo) 在 bash 中做了两件事。首先,它创建一个文件描述符以传递给被调用的命令。它做的第二件事是将/dev/fd/n 作为参数传递。为了确认,请尝试:

echo <(echo foo) <(echo bar)

Echo 忽略 fds,只将文件描述符打印为字符串。

下面的 Go 代码会做类似的事情:

package main

import (
    "io"
    "log"
    "os"
    "os/exec"
    "strings"
)

func main() {
    cmd := exec.Command("diff", "/dev/fd/3", "/dev/fd/4")

    foo, err := readerFile(strings.NewReader("foo\n"))
    if err != nil {
        log.Fatal(err)
    }
    defer foo.Close()

    bar, err := readerFile(strings.NewReader("bar\n"))
    if err != nil {
        log.Fatal(err)
    }
    defer bar.Close()

    cmd.ExtraFiles = []*os.File{foo, bar}

    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    err = cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
}

func readerFile(r io.Reader) (*os.File, error) {
    reader, writer, err := os.Pipe()

    if err != nil {
        return nil, err
    }

    go func() {
        io.Copy(writer, r)
        writer.Close()
    }()

    return reader, nil
}

显然,这只能在类 Unix 系统上运行,因此不是很跨平台。不过,它不受代码注入(inject)的影响。


GIT 的方式

Git 只是制作临时文件然后比较它们。这是非常跨平台的,并且不受注入(inject)影响。只需使用 ioutil.TempFile创建这两个文件,然后运行 ​​exec.Command("diff", file1, file2)

关于使用 <(..) 参数执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29022974/

相关文章:

golang 竞争条件 - 在 2 个 goroutines 中编码为 XML

go - 使用 Go 将文件移动到不同的驱动器

golang中的json解码用于复杂的json数据

PHP exec $PATH 变量缺少元素

c++ - 在 Qt 中如何将模态对话框窗口转换为非模态对话框窗口?

php - 如何以特定 Windows 用户身份从 PHP 网站运行可执行文件?

c - 如何通过调用 exec 函数族的成员来获取程序运行的返回值?

go - 如何测量gRPC响应的大小

io - 如何从 Reader 获取字符串?

sql - 点击按钮执行sql查询