英文:
Start detached command with redirect to file
问题
我正在尝试启动一个分离的进程,以便在Go程序退出后它可以继续运行。我需要将命令的输出重定向到一个文件。
我需要的是这样的代码:
func main() {
command := exec.Command("/tmp/test.sh", ">", "/tmp/out")
if err := command.Start(); err != nil {
fmt.Fprintln(os.Stderr, "Command failed.", err)
os.Exit(1)
}
fmt.Println("Process ID:", command.Process.Pid)
}
显然,这样的重定向是不起作用的。因为我在启动长时间运行的命令后立即退出程序,所以我无法打开一个文件并将其绑定到Stdout。
有没有办法实现这样的重定向呢?
英文:
I'm trying to start a command in a detached process so that it can continue after go program exits. I need to redirect the output of the command to a file.
What I need is something like this:
func main() {
command := exec.Command("/tmp/test.sh", ">", "/tmp/out")
if err := command.Start(); err != nil {
fmt.Fprintln(os.Stderr, "Command failed.", err)
os.Exit(1)
}
fmt.Println("Process ID:", command.Process.Pid)
}
Obviously such redirect doesn't work. As I immediately exit from the program after starting the long running command, I cannot open a file and bind it to the Stdout.
Is there any way to achieve such a redirect?
答案1
得分: 5
您可以启动一个执行您的命令/应用程序的 shell,并将其输出重定向到一个文件。即使您的 Go 应用程序退出,shell 也会继续运行和执行您的脚本/应用程序。
示例:
cmd := exec.Command("sh", "-c", "/tmp/test.sh > /tmp/out")
if err := cmd.Start(); err != nil {
panic(err)
}
fmt.Println("进程 ID:", cmd.Process.Pid)
使用这个简单的 Go 应用程序进行测试(将 /tmp/test.sh
替换为您将其编译为的可执行二进制文件的名称):
package main
import (
"fmt"
"time"
)
func main() {
for i := 0; i < 10; i++ {
fmt.Printf("%d.: %v\n", i, time.Now())
time.Sleep(time.Second)
}
}
这个应用程序每秒钟向标准输出打印一行。您可以使用 tail -f /tmp/out
命令查看输出文件的内容。
请注意,您可以使用其他 shell 来执行您喜欢的脚本(以及 test.sh
脚本所指定的内容)。
例如,要使用 bash
:
cmd := exec.Command("/bin/bash", "-c", "/tmp/test.sh > /tmp/out")
// 其余部分保持不变
请注意,要由 shell 执行的命令作为单个 string
参数传递,并且不会像在命令提示符中直接执行时那样被分解为多个部分。
英文:
You may start a shell which executes your command / app, and you may redirect its output to a file. The shell will continue to run and execute your script / app even if your Go app exits.
Example:
cmd := exec.Command("sh", "-c", "/tmp/test.sh > /tmp/out")
if err := cmd.Start(); err != nil {
panic(err)
}
fmt.Println("Process ID:", cmd.Process.Pid)
Test it with this simple Go app (replace /tmp/test.sh
with the name of the executable binary you compile this into):
package main
import ("fmt"; "time")
func main() {
for i := 0; i < 10; i++ {
fmt.Printf("%d.: %v\n", i, time.Now())
time.Sleep(time.Second)
}
}
This app simply prints a line to the standard output once every second. You can see how the output file is being written e.g. with tail -f /tmp/out
.
Note that you may use other shells to execute your scripts to your liking (and to what the test.sh
script dictates).
For example to use bash
:
cmd := exec.Command("/bin/bash", "-c", "/tmp/test.sh > /tmp/out")
// rest is unchanged
Note that the command to be executed by the shell is passed as a single string
argument, and it is not broken down into multiple as you would do it if you were to execute it directly in the command prompt.
答案2
得分: 4
也许你可以尝试使用这个链接中的方法:https://stackoverflow.com/a/28918814/2728768
打开一个文件(os.File
实现了 io.Writer
),然后将其作为 command.Stdout
参数传递,可能会解决问题:
func main() {
command := exec.Command("./tmp/test.sh")
f, err := os.OpenFile("/tmp/out", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("打开文件时出错:%v", err)
}
defer f.Close()
// 在这一行将输出重定向到文件
command.Stdout = f
if err := command.Start(); err != nil {
fmt.Fprintln(os.Stderr, "命令执行失败:", err)
os.Exit(1)
}
fmt.Println("进程 ID:", command.Process.Pid)
}
不确定这是否适用于你的情况。我在本地尝试过,似乎可以正常工作...请记住,你的用户应该有权限创建/更新文件。
英文:
Maybe you can try to use this: https://stackoverflow.com/a/28918814/2728768
Opening a file (and os.File
implements io.Writer
), and then passing it as the command.Stdout
could do the trick:
func main() {
command := exec.Command("./tmp/test.sh")
f, err := os.OpenFile("/tmp/out", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("error opening file: %v", err)
}
defer f.Close()
// On this line you're going to redirect the output to a file
command.Stdout = f
if err := command.Start(); err != nil {
fmt.Fprintln(os.Stderr, "Command failed.", err)
os.Exit(1)
}
fmt.Println("Process ID:", command.Process.Pid)
}
Not sure this could be a viable solution for your case. I've tried it locally and it seems working... remember that your user should be able to create/update the file.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论