英文:
Cannot run `op` from Go application
问题
我正在尝试编写一个围绕1Password CLI可执行文件op
的小型Go包装应用程序,代码如下:
package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
op := exec.Command("op", "item", "list")
out, err := op.Output()
if e, ok := err.(*exec.ExitError); ok {
log.Fatal(e, ": ", string(e.Stderr))
}
fmt.Println(string(out))
}
然而,我一直收到以下错误:
2023/04/13 09:48:51 exit status 1: [ERROR] 2023/04/13 09:48:51 error initializing client: connecting to desktop app: read: connection reset, make sure the CLI is correctly installed and Connect with 1Password CLI is enabled in the 1Password app
但是,当我用Python脚本做同样的事情时,代码如下:
#!/usr/bin/env python
import subprocess
subprocess.run(["op", "item", "list"])
...我可以正常获得输出。
有趣的是,当我从Go应用程序中调用Python脚本(命名为op.py
)时,它可以正常工作(修改后的Go应用程序如下所示):
package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
op := exec.Command("/usr/bin/python3.11", "./op.py")
//op := exec.Command("op", "item", "list")
out, err := op.Output()
if e, ok := err.(*exec.ExitError); ok {
log.Fatal(e, ": ", string(e.Stderr))
}
fmt.Println(string(out))
}
我可以通过删除fmt.Printf(...)
来测试是Go应用程序打印的输出,如果删除该语句,将不会打印任何内容。
所以总结一下:
- Go ->
op
:不起作用 - Python (
./op.py
) ->op
:正常工作 - Go -> Python (
./op.py
) ->op
:正常工作
英文:
I am trying to write a small Go wrapper application around the 1Password CLI executable op
like so:
package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
op := exec.Command("op", "item", "list")
out, err := op.Output()
if e, ok := err.(*exec.ExitError); ok {
log.Fatal(e, ": ", string(e.Stderr))
}
fmt.Println(string(out))
}
However, I keep getting the following error:
2023/04/13 09:48:51 exit status 1: [ERROR] 2023/04/13 09:48:51 error initializing client: connecting to desktop app: read: connection reset, make sure the CLI is correctly installed and Connect with 1Password CLI is enabled in the 1Password app
But when I do the same thing from a Python script like so:
#!/usr/bin/env python
import subprocess
subprocess.run(["op", "item", "list"])
...I get the output just fine.
Interestingly enough though, when I call the Python script (named op.py
) from the Go app, it works fine (modified Go app shown below):
package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
op := exec.Command("/usr/bin/python3.11", "./op.py")
//op := exec.Command("op", "item", "list")
out, err := op.Output()
if e, ok := err.(*exec.ExitError); ok {
log.Fatal(e, ": ", string(e.Stderr))
}
fmt.Println(string(out))
}
I can test that it is being printed by the Go app and not by the Python script because if I remove the fmt.Printf(...)
, nothing gets printed.
So to summarize:
- Go ->
op
: does not work - Python (
./op.py
) ->op
: works fine - Go -> Python (
./op.py
) ->op
: works fine
答案1
得分: 2
我在一个pyenv
虚拟环境中遇到了同样的问题,无法访问op
。我发现问题是因为pyenv的python
可执行文件的所有者是用户(我自己)。
将python解释器及其所在的目录的所有权更改为root:root实际上有所帮助。不确定背后发生了什么。
以下是步骤(我使用--copies
来创建虚拟环境,因此不使用符号链接,因为符号链接会指向root拥有的文件):
$ python -m venv --copies .venv
$ .venv/bin/python -c "import subprocess; subprocess.call(['op', 'signin'])"
[ERROR] 2023/05/16 16:01:18 connecting to desktop app: read: connection reset, make sure the CLI is correctly installed and Connect with 1Password CLI is enabled in the 1Password app
# chown -R root:root .venv/
$ .venv/bin/python -c "import subprocess; subprocess.call(['op', 'signin'])"
Select account [Use arrows to move, type to filter]
要点是:将生成op
子进程的可执行文件(及其所在的目录)的所有权更改为root:root
。
此外,请参阅1Password上看起来是相同问题的讨论线程:
https://1password.community/discussion/135768/calling-the-cli-from-a-go-program
英文:
I had the same problem accessing op
from a pyenv
virtual environment. I figured that the problem is that the pyenv's python
executable is owned by the user (me).
Changing the ownership to root:root of the python interpreter and the directory that it lives in actually helped. Not sure what is going on behind the scenes.
Here are the steps (I use the --copies
to create a virtual environment, so it is not using symlinks - as symlinks would point back to root owned files):
$ python -m venv --copies .venv
$ .venv/bin/python -c "import subprocess; subprocess.call(['op', 'signin'])"
[ERROR] 2023/05/16 16:01:18 connecting to desktop app: read: connection reset, make sure the CLI is correctly installed and Connect with 1Password CLI is enabled in the 1Password app
# chown -R root:root .venv/
$ .venv/bin/python -c "import subprocess; subprocess.call(['op', 'signin'])"
Select account [Use arrows to move, type to filter]
Bottomline: Change the ownership of your executable (and directory it lives in) that spawns the op
subprocess to root:root
Also please see this thread on 1Password that look like the same issue:
https://1password.community/discussion/135768/calling-the-cli-from-a-go-program
答案2
得分: -2
我实际上正在使用GoLang作为一个覆盖GUI应用程序,它与几个不同的cpp二进制文件通信,作为一个集中控制器。我已经实现了以下函数来运行通用命令:
func RunCmd(binary string, cmd []string) []string {
var output []string
c, b := exec.Command(binary, cmd...), new(bytes.Buffer)
c.Stdout = b
c.Run()
s := bufio.NewScanner(b)
for s.Scan() {
output = append(output, s.Text())
}
return output
}
这个函数运行命令并将输出作为字符串切片返回(每行一个字符串)。以下是调用它的示例:
_ = RunCmd("./moveRobot", []string{"10.20.0.37", localIP.String(), "align"})
在你的示例中,你可以这样调用它:
out = RunCmd("op", []string{"item", "get", "DocSend", "--format=json"})
但是,你可能还需要提供op
二进制文件的路径,所以我建议尝试一下(如果它在同一个目录下,可以使用./op
)。
显然,这个函数并不直接返回JSON格式的输出,但你可以将其作为起点,至少确认调用是否正常工作。
英文:
I'm actually using GoLang as an overlaying GUI application which communicates with several distinct cpp binaries as a centralised controller. I've implemented the following function to run generic commands:
func RunCmd(binary string, cmd []string) []string {
var output []string
c, b := exec.Command(binary, cmd...), new(bytes.Buffer)
c.Stdout = b
c.Run()
s := bufio.NewScanner(b)
for s.Scan() {
output = append(output, s.Text())
}
return output
}
This function runs the command and returns the output as a slice of strings (one per line of output). Here's an example of calling it:
_ = RunCmd("./moveRobot", []string{"10.20.0.37", localIP.String(), "align"})
In your example, you would call it as:
out = RunCmd("op", []string{"item", "get", "DocSend", "--format=json"})
It is also possible that you need to provide the path to the op
binary however, so I would try that (if it's in the same directory, then use ./op
This obviously doesn't return the output in JSON as is, but you can use it as a starting point to at least confirm the call is working.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论