如何在Go中输出流程替换文件?

时间:2016-03-19 14:06:33

标签: go

我必须遗漏一些基本的东西,因为以下内容没有按预期工作。

bash或zsh下的

go run test_fd.go <(cat)会产生以下结果:

预期输出

$ go run test_fd.go <(cat) # where n is some fd number
fd {{n}} filename /dev/fd/{{n}}
Hello!

实际输出(Zsh)

$ go run test_fd.go <(cat)
fd 11 filename /dev/fd/11
panic: Write() err write /dev/fd/11: bad file descriptor

goroutine 1 [running]:
panic(0xefe80, 0xc820010200)
    /usr/local/Cellar/go/1.6/libexec/src/runtime/panic.go:464 +0x3e6
main.main()
    /Users/bmf/Projects/piper/main.go:32 +0x515
exit status 2

实际输出(Bash)

$ go run main.go <(cat)
fd 63 filename /dev/fd/63
panic: Write() err write /dev/fd/63: bad file descriptor

goroutine 1 [running]:
panic(0xefe80, 0xc82006c240)
    /usr/local/Cellar/go/1.6/libexec/src/runtime/panic.go:464 +0x3e6
main.main()
    /Users/bmf/Projects/piper/main.go:32 +0x515
exit status 2

来源

// test_fd.go
package main

import (
  "fmt"
  "os"
  "regexp"
  "strconv"
)

var fdRegex = regexp.MustCompile(`\A/dev/fd/(\d+)\z`)

func main() {
  for _, filename := range os.Args {

    fdStrMatch := fdRegex.FindStringSubmatch(filename)
    if len(fdStrMatch) != 2 {
      continue
    }
    fd, _ := strconv.Atoi(fdStrMatch[1]) // fdStrMatch[1] is \d+
    fmt.Fprintf(os.Stderr, "fd %d filename %s\n", fd, filename)
    f := os.NewFile(uintptr(fd), filename)
    /*
        f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0777) // have tried many combinations of modes 
      if err != nil {
        panic(fmt.Sprintf("Create() err %v", err))
      }
    */
    _, err := f.Write([]byte("Hello!\n"))
    if err != nil {
      panic(fmt.Sprintf("Write() err %v", err))
    }
  }
}

1 个答案:

答案 0 :(得分:1)

错误的流程替代形式:

$ go run test_fd.go >(cat)

  • <(...)通过某个文件从进程只读,通常是/dev/fd/*
  • >(...)来自流程的只写通过某个文件/dev/fd/*