eber
V2EX  ›  Go 编程语言

各位爹,请教一个 golang 的问题!

By eber at 2024 年 3 月 18 日 · 4228 次点击

各位 golang 大佬(爹),上午好!我有个菜鸡问题:如何使用 golang 的 exec.Command()函数执行 sudo ?

背景:小弟在使用 chromedp 做一个爬虫,目前一切正常,唯一的遗憾就是每次运行之前需要手动在 macOS 的终端执行 sudo /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=19222 必须加 sudo 才能打开 chrome 调试窗口。因为 golang 可以执行终端命令,所以我想使用代码去唤醒调试窗口,但是测试下来好像无法全自动调用 sudo 命令(不输入密码或密码怎么传进去)。

29 条回复  •  2024-03-20 10:08:13 +08:00
NessajCN
   1
NessajCN  
   2024 年 3 月 18 日   ❤️ 2
你用 sudo 执行爬虫程序不就好了
imPrk
   2
imPrk  
   2024 年 3 月 18 日
cmd := exec.Command("sudo", "ls", "/root")
eber
   3
eber  
OP
   2024 年 3 月 18 日
@imPrk 试过了,不行。。。会一直卡住,因为没输入密码。
pkoukk
   4
pkoukk  
   2024 年 3 月 18 日
go build -o main .
sudo ./main
eber
   5
eber  
OP
   2024 年 3 月 18 日
@NessajCN 刚试了一下,sudo 执行程序还是不会弹出 chrome 调试页。19222 也没有在监听。
dummyx
   6
dummyx  
   2024 年 3 月 18 日
你把运行用户的 sudo 设置 NOPASSWD 不就行了嘛。。
imPrk
   7
imPrk  
   2024 年 3 月 18 日
@eber 你确定你的 Go 程式有使用 root 身份运行吗
JEME
   8
JEME  
   2024 年 3 月 18 日
使用 pty 相关的库,应该可以?
aloxaf
   9
aloxaf  
   2024 年 3 月 18 日
用 sudo -S 可以从标准输入接收密码,然后你就可以正常把密码传进去了
yanghanlin
   10
yanghanlin  
   2024 年 3 月 18 日 via Android
sudo -S 然后密码通过 stdin 传进去?
eber
   11
eber  
OP
   2024 年 3 月 18 日
@NessajCN 抱歉,抱歉。。。找到问题了,确实 sudo 运行程序可以唤醒调试页面。应该是 chrome 路径问题。。。/Applications/Google Chrome.app/Contents/MacOS/Google Chrome 空格不能加转译。。。
Yangsh853
   12
Yangsh853  
   2024 年 3 月 18 日
在 sudoers 给用户加 NOPASSWD ,就不用输密码了
eber
   13
eber  
OP
   2024 年 3 月 18 日
是的,这样确实可以,但是需要提前修改用户属性不太好。
@fengxsong
@Yangsh853
eber
   14
eber  
OP
   2024 年 3 月 18 日
@JEME 我去试一下先,有结果了我来说一下。
eber
   15
eber  
OP
   2024 年 3 月 18 日
@yanghanlin
@aloxaf 也是个不错方法。
somebody1
   16
somebody1  
   2024 年 3 月 18 日   ❤️ 2
这是学到精髓了呀,上周的那个帖子上大分!
wOuv7i4e7XxsSOR1
   17
wOuv7i4e7XxsSOR1  
   2024 年 3 月 18 日
sudo -A
proxychains
   18
proxychains  
   2024 年 3 月 18 日 via Android
提问的艺术
cat9life
   19
cat9life  
   2024 年 3 月 18 日
辈分有点乱啊,一会爹一会自称小弟。(开个玩笑..
lele140
   20
lele140  
   2024 年 3 月 18 日
现在 问问题都这么卷了吗?
deplives
   21
deplives  
   2024 年 3 月 18 日
sudo 可以使用 -S 从 stdin 传入密码
eber
   22
eber  
OP
   2024 年 3 月 18 日   ❤️ 1
@lele140 虚心学习嘛 不磕碜!!!
Leeeeex
   23
Leeeeex  
   2024 年 3 月 18 日
提问的艺术得更新了
2Nfree
   24
2Nfree  
   2024 年 3 月 18 日
golang.org/x/crypto/ssh 包可以创建标准管道输出
用 session.StdinPipe()
2Nfree
   25
2Nfree  
   2024 年 3 月 18 日
@2Nfree 用这个办法可以输入 sudo 的密码,之前写过一个模仿 ansiable 的程序是这么做的,里面部分代码:
package utils

import (
"batch-execution-tool/core"
"bytes"
"fmt"
"golang.org/x/crypto/ssh"
"os"
"sync"
)

func ExecuteScripts() {
var wg sync.WaitGroup
defer wg.Wait()
for _, ip := range core.Config.ServersIP {
wg.Add(1)
go func(ip string) {
defer wg.Done()
SSHClient, errSSH := createSSHConnect(ip)
if errSSH != nil {
core.Logger.Sugar().Errorf("创建 SSH 链接失败:\n%v", errSSH)
return
}
for _, script := range core.Config.Scripts {
for name := range script {
err := exec(SSHClient, ip, name)
if err != nil {
core.Logger.Sugar().Errorf("在 IP 地址为:%v 的服务器,出现错误:\n%v", ip, err)
} else {
core.Logger.Sugar().Debugf("在 IP 地址为:%v 的服务器,执行脚本 %v 成功", ip, name)
}
}
}
}(ip)
}
}

func exec(client *ssh.Client, ip, script string) error {
core.Logger.Sugar().Debugf("正在 IP 地址为:%v 的服务器中执行脚本:%s", ip, script)
session, err := client.NewSession()
if err != nil {
return err
}
var output bytes.Buffer
session.Stderr = &output
remoteDir := "scripts"
if core.Config.Auth.Username == "root" {
if err := session.Start("bash " + remoteDir + "/" + script + " > " + remoteDir + "/" + script + ".log"); err != nil {
return fmt.Errorf("执行脚本 %s 失败: \n%s:%s", script, err, output.String())
}
if err := session.Wait(); err != nil {
return fmt.Errorf("执行脚本 %s 失败: \n%s:%s", script, err, output.String())
}
} else {
if err := session.RequestPty("xterm", 80, 40, ssh.TerminalModes{}); err != nil {
return fmt.Errorf("请求 TTY 出错:%v ,\nos.Stderr:%v", err, os.Stderr)
}
stdin, err := session.StdinPipe()
defer stdin.Close()
if err != nil {
return fmt.Errorf("创建标准管道输出错误: \n%v", err)
}
if err := session.Start("sudo bash " + remoteDir + "/" + script + " > " + remoteDir + "/" + script + ".log"); err != nil {
return fmt.Errorf("执行脚本 %s 失败: \n%s:%s", script, err, output.String())
}
_, err = fmt.Fprintln(stdin, core.Config.Auth.Password)
if err != nil {
return fmt.Errorf("使用标准管道输如密码错误: \n%v", err)
}
if err := session.Wait(); err != nil {
return fmt.Errorf("执行脚本 %s 失败: \n%s:%s", script, err, output.String())
}
}
session.Close()
return nil
}
eber
   26
eber  
OP
   2024 年 3 月 18 日
@chanChristin 看来下次还要再长一个辈分才行了!😂

@2Nfree 好的,抽空我试试。
danhahaha
   27
danhahaha  
   2024 年 3 月 18 日
连续俩帖子把我震住了,态度如此诚恳,此子必成大器
danbai
   28
danbai  
PRO
   2024 年 3 月 19 日 via Android
哥们都用 golang 了你可以用用 rod 这个库
eber
   29
eber  
OP
   2024 年 3 月 20 日
@danbai 兄弟我来还愿了。经过这两天的体验,rod 库确实用起来比 chromedp 方便多了!
The Go Programming Language
› http://golang.org/
› Go Playground
Go Projects
› Revel Web Framework
© 2026 V2EX · 59ms · 3.9.8.5