Почему в Go происходит сбой exec.Command(), но os.StartProcess() успешно запускает «winget.exe»?

  • работает на выполнение C:\Windows\System32\notepad.exe
  • Но exec.Command()не работает для выполнения. Сбой с сообщением об ошибке:
    • exec: "C:\\Users\\<username>\\AppData\\Local\\Microsoft\\WindowsApps\\winget.exe": file does not exist
  • Однако, os.StartProcess()работает на выполнение C:\Users\<username>\AppData\Local\Microsoft\WindowsApps\winget.exe

Может кто-нибудь сказать мне, почему?

Этот фрагмент кода не работает. winget.exeне запускается.

      wingetPath := filepath.Join(os.Getenv("LOCALAPPDATA"),
    "Microsoft\\WindowsApps\\winget.exe")
cmd := exec.Command(wingetPath, "--version")
err := cmd.Start()
fmt.Println(err)
// exec: "C:\\Users\\<username>\\AppData\\Local\\Microsoft\\WindowsApps\\winget.exe": file does not exist

Но это работает:

      wingetPath := filepath.Join(os.Getenv("LOCALAPPDATA"),
    "Microsoft\\WindowsApps\\winget.exe")
procAttr := new(os.ProcAttr)
procAttr.Files = []*os.File{nil, nil, nil}

// The argv slice will become os.Args in the new process,
// so it normally starts with the program name
_, err := os.StartProcess(wingetPath, []string{wingetPath, "--version"}, procAttr)
fmt.Println(err)
// <nil>

Перейти версии:

      > go version
go version go1.18 windows/amd64

1 ответ

Ошибка в Голанге

Так что, видимо, это ошибка в реализации Windows Goи был зарегистрирован на GitHub много раз — самый старый, который я мог найти, — это проблема , которая была зарегистрирована много лет назад.

Ошибка вызвана тем, что exec.Command()внутренне использует os.Stat()который не читает файлы с точками повторной обработки правильно. os.Lstat()Можно.

Приложения Магазина Windows используют псевдонимы выполнения приложений , которые по сути представляют собой файлы с нулевым байтом и точками повторной обработки. Этот пост содержит некоторые дополнительные детали.

Обходные пути

  • Обходной путь заключается в использовании os.StartProces()- API более низкого уровня, который может быть немного болезненным в использовании, особенно по сравнению с os.Exec().
    Важно : в os.StartProcess(), срез argv станет os.Argsв новом процессе, поэтому обычно вы должны передавать имя программы в качестве первого аргумента:
      wingetPath := filepath.Join(os.Getenv("LOCALAPPDATA"),
    "Microsoft\\WindowsApps\\winget.exe")
procAttr := new(os.ProcAttr)
procAttr.Files = []*os.File{nil, nil, nil}
/*
To redirect IO, pass in stdin, stdout, stderr as required
procAttr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr}
*/

args = []string { "install", "git.git" }

// The argv slice will become os.Args in the new process,
// so it normally starts with the program name
proc, err := os.StartProcess(wingetPath,
   append([]string{wingetPath}, arg...), procAttr)
fmt.Println(err) // nil
  • Другой способ обойти эту ошибку состоит в том, чтобы (создать и) выполнить .cmdфайл (например), который будет (правильно разрешать и) выполнять файл с точками повторной обработки. См. это (а также этот каталог ) для примера.
Другие вопросы по тегам