How to output to a process substitution file in Go?

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

How to output to a process substitution file in Go?

问题

我一定是漏掉了一些基本的东西,因为以下代码没有按预期工作。

在bash或zsh下运行go run test_fd.go <(cat)会导致以下结果:

预期输出

<!-- language: lang-none -->

  1. $ go run test_fd.go &lt;(cat) # 其中n是某个文件描述符号
  2. fd {{n}} 文件名 /dev/fd/{{n}}
  3. Hello!

实际输出(Zsh)

<!-- language: lang-none -->

  1. $ go run test_fd.go &lt;(cat)
  2. fd 11 文件名 /dev/fd/11
  3. panic: Write() err write /dev/fd/11: bad file descriptor
  4. goroutine 1 [running]:
  5. panic(0xefe80, 0xc820010200)
  6. /usr/local/Cellar/go/1.6/libexec/src/runtime/panic.go:464 +0x3e6
  7. main.main()
  8. /Users/bmf/Projects/piper/main.go:32 +0x515
  9. exit status 2

实际输出(Bash)

<!-- language: lang-none -->

  1. $ go run main.go &lt;(cat)
  2. fd 63 文件名 /dev/fd/63
  3. panic: Write() err write /dev/fd/63: bad file descriptor
  4. goroutine 1 [running]:
  5. panic(0xefe80, 0xc82006c240)
  6. /usr/local/Cellar/go/1.6/libexec/src/runtime/panic.go:464 +0x3e6
  7. main.main()
  8. /Users/bmf/Projects/piper/main.go:32 +0x515
  9. exit status 2

源代码

  1. // test_fd.go
  2. package main
  3. import (
  4. "fmt"
  5. "os"
  6. "regexp"
  7. "strconv"
  8. )
  9. var fdRegex = regexp.MustCompile(`\A/dev/fd/(\d+)\z`)
  10. func main() {
  11. for _, filename := range os.Args {
  12. fdStrMatch := fdRegex.FindStringSubmatch(filename)
  13. if len(fdStrMatch) != 2 {
  14. continue
  15. }
  16. fd, _ := strconv.Atoi(fdStrMatch[1]) // fdStrMatch[1] 是 \d+
  17. fmt.Fprintf(os.Stderr, "fd %d 文件名 %s\n", fd, filename)
  18. f := os.NewFile(uintptr(fd), filename)
  19. /*
  20. f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0777) // have tried many combinations of modes
  21. if err != nil {
  22. panic(fmt.Sprintf("Create() err %v", err))
  23. }
  24. */
  25. _, err := f.Write([]byte("Hello!\n"))
  26. if err != nil {
  27. panic(fmt.Sprintf("Write() err %v", err))
  28. }
  29. }
  30. }
英文:

I must missing something basic because the following is not working as expected.

go run test_fd.go &lt;(cat) under either bash or zsh results in the following:

Expected output

<!-- language: lang-none -->

  1. $ go run test_fd.go &lt;(cat) # where n is some fd number
  2. fd {{n}} filename /dev/fd/{{n}}
  3. Hello!

Actual output (Zsh)

<!-- language: lang-none -->

  1. $ go run test_fd.go &lt;(cat)
  2. fd 11 filename /dev/fd/11
  3. panic: Write() err write /dev/fd/11: bad file descriptor
  4. goroutine 1 [running]:
  5. panic(0xefe80, 0xc820010200)
  6. /usr/local/Cellar/go/1.6/libexec/src/runtime/panic.go:464 +0x3e6
  7. main.main()
  8. /Users/bmf/Projects/piper/main.go:32 +0x515
  9. exit status 2

Actual output (Bash)

<!-- language: lang-none -->

  1. $ go run main.go &lt;(cat)
  2. fd 63 filename /dev/fd/63
  3. panic: Write() err write /dev/fd/63: bad file descriptor
  4. goroutine 1 [running]:
  5. panic(0xefe80, 0xc82006c240)
  6. /usr/local/Cellar/go/1.6/libexec/src/runtime/panic.go:464 +0x3e6
  7. main.main()
  8. /Users/bmf/Projects/piper/main.go:32 +0x515
  9. exit status 2

Source

  1. // test_fd.go
  2. package main
  3. import (
  4. &quot;fmt&quot;
  5. &quot;os&quot;
  6. &quot;regexp&quot;
  7. &quot;strconv&quot;
  8. )
  9. var fdRegex = regexp.MustCompile(`\A/dev/fd/(\d+)\z`)
  10. func main() {
  11. for _, filename := range os.Args {
  12. fdStrMatch := fdRegex.FindStringSubmatch(filename)
  13. if len(fdStrMatch) != 2 {
  14. continue
  15. }
  16. fd, _ := strconv.Atoi(fdStrMatch[1]) // fdStrMatch[1] is \d+
  17. fmt.Fprintf(os.Stderr, &quot;fd %d filename %s\n&quot;, fd, filename)
  18. f := os.NewFile(uintptr(fd), filename)
  19. /*
  20. f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0777) // have tried many combinations of modes
  21. if err != nil {
  22. panic(fmt.Sprintf(&quot;Create() err %v&quot;, err))
  23. }
  24. */
  25. _, err := f.Write([]byte(&quot;Hello!\n&quot;))
  26. if err != nil {
  27. panic(fmt.Sprintf(&quot;Write() err %v&quot;, err))
  28. }
  29. }
  30. }

答案1

得分: 1

错误的进程替代形式:

$ go run test_fd.go &gt;(cat)

  • &lt;(...) 是通过某个文件从进程中只读读取的,通常是 /dev/fd/*
  • &gt;(...) 是通过某个文件从进程中只写写入的,通常是 /dev/fd/*
英文:

Wrong form of process substitution:

$ go run test_fd.go &gt;(cat)

  • &lt;(...) is read-only from the process via some file, usually /dev/fd/*
  • &gt;(...) is write-only from the process via some file usually /dev/fd/*

huangapple
  • 本文由 发表于 2016年3月19日 22:06:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/36102725.html
匿名

发表评论

匿名网友

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

确定