英文:
How to output to a process substitution file in Go?
问题
我一定是漏掉了一些基本的东西,因为以下代码没有按预期工作。
在bash或zsh下运行go run test_fd.go <(cat)
会导致以下结果:
预期输出
<!-- language: lang-none -->
$ go run test_fd.go <(cat) # 其中n是某个文件描述符号
fd {{n}} 文件名 /dev/fd/{{n}}
Hello!
实际输出(Zsh)
<!-- language: lang-none -->
$ go run test_fd.go <(cat)
fd 11 文件名 /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)
<!-- language: lang-none -->
$ go run main.go <(cat)
fd 63 文件名 /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] 是 \d+
fmt.Fprintf(os.Stderr, "fd %d 文件名 %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))
}
}
}
英文:
I must missing something basic because the following is not working as expected.
go run test_fd.go <(cat)
under either bash or zsh results in the following:
Expected output
<!-- language: lang-none -->
$ go run test_fd.go <(cat) # where n is some fd number
fd {{n}} filename /dev/fd/{{n}}
Hello!
Actual output (Zsh)
<!-- language: lang-none -->
$ 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
Actual output (Bash)
<!-- language: lang-none -->
$ 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
Source
// 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
得分: 1
错误的进程替代形式:
$ go run test_fd.go >(cat)
<(...)
是通过某个文件从进程中只读读取的,通常是/dev/fd/*
>(...)
是通过某个文件从进程中只写写入的,通常是/dev/fd/*
英文:
Wrong form of process substitution:
$ go run test_fd.go >(cat)
<(...)
is read-only from the process via some file, usually/dev/fd/*
>(...)
is write-only from the process via some file usually/dev/fd/*
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论