我如何制作一个可以自动删除的go程序?

我如何制作一个可以自动删除的go程序?,go,Go,这一切都始于我想制作一个可以自我更新的程序。我想我需要该程序下载一个新版本,并运行一个复制新程序并用下载版本替换原始程序的功能 我试图使这个问题尽可能小,如何使一个程序调用另一个程序来删除自己,以下是我的尝试: package main import ( "flag" "fmt" "log" "os" "os/exec" "time" ) func main() { fmt.Println("program started")

这一切都始于我想制作一个可以自我更新的程序。我想我需要该程序下载一个新版本,并运行一个复制新程序并用下载版本替换原始程序的功能

我试图使这个问题尽可能小,如何使一个程序调用另一个程序来删除自己,以下是我的尝试:

package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "os/exec"
    "time"
)

func main()  {
    fmt.Println("program started")
    remove := flag.Bool("rm", false, "removes test")
    flag.Parse()

    if *remove {
        // Wait 5 seconds to let other program finish
        time.Sleep(5 * time.Second)
        // Try to remove program that started this program
        fmt.Println("running rm")
        err := os.Remove("./test")
        if err != nil {
            log.Fatalf("os.Remove() failed with %s\n", err)
        }
    } else {
        // Call the second program which will remove ./test which is currently running
        fmt.Println("running remove program")
        cmd := exec.Command("./remove", "-rm")
        err := cmd.Start()
        if err != nil {
            log.Fatalf("cmd.Run() failed with %s\n", err)
        }
    }
}
下面是我如何通过cli调用它

uberswe$ go build -o test
uberswe$ go build -o remove
uberswe$ ./test
program started
running remove program
uberswe$ ls -la
total 9048
drwxr-xr-x@  6 uberswe  staff      192 Apr 14 15:55 .
drwxr-xr-x@ 56 uberswe  staff     1792 Apr 14 15:36 ..
drwxr-xr-x@  6 uberswe  staff      192 Apr 14 15:55 .idea
-rw-r--r--@  1 uberswe  staff      680 Apr 14 15:55 main.go
-rwxr-xr-x@  1 uberswe  staff  2311528 Apr 14 15:55 remove
-rwxr-xr-x@  1 uberswe  staff  2311528 Apr 14 15:55 test
总之:我如何制作一个程序,该程序可以自行或通过第二个命令/程序删除自身?


如果它可移植到不同的操作系统,则会有额外的好处。

因为您的目标是让应用程序自我更新,所以我会将此功能移到第二个“更新程序”应用程序中。否则,可执行文件(取决于操作系统)可能会被锁定,而且您仍然存在重新启动应用程序的问题。流程如下所示:

  • 主程序生成更新程序并自行终止
  • 更新程序等待主程序终止
  • 更新程序替换可执行文件并重新启动应用程序(如果需要)

下面的代码是我如何解决这个问题的一个例子,它可以在Mac OS、Linux和Windows上运行

package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "os/exec"
    "runtime"
    "time"
)

func main()  {
    fmt.Println("program started")
    remove := flag.Bool("rm", false, "removes test")
    flag.Parse()

    if *remove {
        var err error
        // Wait 5 seconds to let other program finish
        time.Sleep(5 * time.Second)
        // Try to remove program that started this program
        fmt.Println("running rm")
        if runtime.GOOS == "windows" {
            err = os.Remove("./test.exe")
        } else {
            err = os.Remove("./test")
        }
        if err != nil {
            log.Fatalf("os.Remove() failed with %s\n", err)
        }
    } else {
        var cmd *exec.Cmd
        // Call the second remove program which will remove ./test which is currently running
        fmt.Println("running remove program")
        if runtime.GOOS == "windows" {
            cmd = exec.Command("./remove.exe", "-rm")
        } else {
            cmd = exec.Command("./remove", "-rm")
        }
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        err := cmd.Start()
        if err != nil {
            log.Fatalf("cmd.Run() failed with %s\n", err)
        }
    }
    fmt.Println("Finished running program")
}
如果您这样运行该程序,它将自动删除

uberswe$ go build -o test
uberswe$ go build -o remove
uberswe$ ./test

在windows上,我必须做一个更改,即添加.exe扩展名,以便windows cmd将二进制文件识别为可执行文件。我可以让应用程序
测试
调用
删除
来删除自身。

在linux上,您只需从自身管理正在运行的可执行文件即可。在Windows上这并不容易。@tkausl很高兴知道,我也用
cmd.Start()
而不是
cmd.Run()
尝试了这一点,但在Mac OS上测试时仍然没有发生任何事情。为什么你甚至调用
rm
而不是直接从Go中删除文件?@tkausl很好,我已经更新了我的问题,包括了这一点,我现在看到,该文件在mac上也被删除了,但前提是我直接使用
-rm
标记调用我的程序,而不是当
/test
调用
/remove-rm
时,尝试将
cmd.Stdout
cmd.Stderr
设置到您自己的流中以查看被调用程序的输出