Почему в 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