#go
# #Вперед
Вопрос:
Все это началось, когда я захотел создать программу, которая могла бы обновляться. Я подумал, что мне нужна программа для загрузки новой версии и запуска функции, которая копирует новую программу и заменяет оригинал загруженной версией.
Я попытался сделать эту проблему как можно меньше, как я могу создать программу, которая вызывает другую программу для удаления себя, вот моя попытка:
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 %sn", 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 %sn", 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
Итак, вкратце: как я могу создать программу, которая может удалять себя самостоятельно или с помощью второй команды / программы?
Бонус, если он переносим на разные операционные системы.
Комментарии:
1. В Linux вы можете просто перезаписать запущенный исполняемый файл из самого себя. В Windows это не так просто.
2. @tkausl полезно знать, я также пробовал это с
cmd.Start()
помощью instead ofcmd.Run()
, и все равно ничего не происходит, когда я тестирую на Mac OS.3. Почему вы даже вызываете
rm
вместо того, чтобы удалять файл из Go напрямую?4. @tkausl хороший момент, я обновил свой вопрос, чтобы включить это, теперь я вижу, что файл также удаляется на Mac, но только если я вызываю свою программу с
-rm
помощью флага напрямую, а не при./test
вызовах./remove -rm
5. Попробуйте настроить
cmd.Stdout
иcmd.Stderr
для своих собственных потоков, чтобы увидеть результат вызываемой программы
Ответ №1:
Поскольку ваша цель состоит в том, чтобы приложение обновляло себя, я бы перенес эту функциональность во второе приложение «обновления». Исполняемый файл (в зависимости от ОС) может быть заблокирован в противном случае, плюс у вас все еще есть проблема с перезапуском приложения. Поток будет таким:
- основная программа запускает программу обновления и завершает работу
- программа обновления ожидает завершения основной программы
- программа обновления заменяет исполняемый файл и перезапускает приложение (при желании)
Ответ №2:
Итак, примером того, как я могу решить эту проблему, которая работает на 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 %sn", 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 %sn", err)
}
}
fmt.Println("Finished running program")
}
Эта программа удалит себя, если вы запустите ее следующим образом
uberswe$ go build -o test
uberswe$ go build -o remove
uberswe$ ./test
В Windows мне пришлось внести одно изменение, которое заключается в добавлении расширения .exe, чтобы Windows cmd распознала двоичный файл как исполняемый файл. Я смог заставить приложение test
вызывать remove
для удаления себя.