英文:
How to run a foreground or background shell command in Go
问题
在Go语言中,我需要能够从用户那里运行一个shell命令,并且只阻塞在前台运行的命令(不使用&
运行),同时获取命令的输出。
例如,在Bash中,我们可以这样写:
#!/bin/bash
while read -p 'enter a command: ' cmd; do
/bin/sh -c "$cmd" >(sed 's/^/line of output: /')
done
用户可以输入一个前台命令,比如 sleep 5; echo hi
,它会阻塞并且提示符不会立即重新出现,或者他们可以输入一个后台命令,比如 { sleep 5; echo hi; } &
,它不会阻塞并且提示符会立即重新出现,因为命令在后台运行。
我该如何在Go中重新创建这个功能?以下是我的尝试:
package main
import (
"bufio"
"os"
"os/exec"
)
func main() {
input := bufio.NewScanner(os.Stdin)
for {
print("enter a command: ")
input.Scan()
cmd := exec.Command("/bin/sh", "-c", input.Text())
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
go func() {
output := bufio.NewScanner(stdout)
for output.Scan() {
println("line of output: " + output.Text())
}
if output.Err() != nil {
panic(output.Err())
}
}()
if err := cmd.Start(); err != nil {
panic(err)
}
if err := cmd.Wait(); err != nil {
panic(err)
}
}
}
运行 sleep 5; echo hi
会阻塞并且正常工作,但是 { sleep 5; echo hi; } &
会报错:
panic: read |0: file already closed
背景信息:我正在将语音控制移植到Go语言中,用户可以配置诸如 runtype
的操作,其中他们的命令通过shell运行,并模拟按键输入输出。用户可以使用后台命令,以便在命令执行时语音控制仍然继续进行,例如,他们可以在说“menu”时启动一个菜单,并且仍然能够在菜单打开时使用语音控制,命令示例:menu: runtype printf %s\\n this that | dmenu &
。
英文:
In Go, I need to be able to run a shell command from the user, and to only block for commands run in the foreground (not run with &
), while retrieving the output of the command.
For example, in Bash we can have:
#!/bin/bash
while read -p 'enter a command: ' cmd; do
/bin/sh -c "$cmd" >(sed 's/^/line of output: /')
done
The user can enter a foreground command like sleep 5; echo hi
and it will block and the prompt won't reappear instantly, or they can enter a background command like { sleep 5; echo hi; } &
and it won't block and the prompt will reappear instantly as the command runs in the background.
How would I recreate this in Go? Here is my attempt:
package main
import (
"bufio"
"os"
"os/exec"
)
func main() {
input := bufio.NewScanner(os.Stdin)
for {
print("enter a command: ")
input.Scan()
cmd := exec.Command("/bin/sh", "-c", input.Text())
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
go func() {
output := bufio.NewScanner(stdout)
for output.Scan() {
println("line of output: " + output.Text())
}
if output.Err() != nil {
panic(output.Err())
}
}()
if err := cmd.Start(); err != nil {
panic(err)
}
if err := cmd.Wait(); err != nil {
panic(err)
}
}
}
Running sleep 5; echo hi
blocks and works, but { sleep 5; echo hi; } &
errors with:
panic: read |0: file already closed
For context, I'm porting voice control to Go, where the user can configure actions such as runtype
, where their command is run through the shell and keys are simulated to type the output. The user can use a background command so the voice control continues along with the command, for example, they can have it launch a menu when they say "menu" and still be able to use the voice control while it's open with: menu: runtype printf %s\\n this that | dmenu &
.
答案1
得分: 0
将stdout设置为命名管道实现了这种行为。
英文:
Setting stdout to a named pipe achieved the behavior.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论