去执行<(..)参数

时间:2015-03-13 00:46:57

标签: 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

2 个答案:

答案 0 :(得分:4)

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

&lt;(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的系统,因此不是非常跨平台的。但它不受代码注入的影响。


GIT的方式

Git只生成临时文件然后进行比较。这是非常跨平台的,对注射免疫。只需使用ioutil.TempFile创建两个文件,然后运行exec.Command("diff", file1, file2)

答案 1 :(得分:3)

<(echo foo)语法由shell shbash解释。函数exec.Command不会在您提供的参数上调用shell,而是直接执行进程。如果要调用shell,则调用shell:

exec.Command("bash", "-c", "diff <(echo foo) </echo bar)")

在此示例中,我在许多系统上使用bashsh未实现<(cmd)语法。尽量使用sh来提高应用程序的可移植性。