V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
eber
V2EX  ›  Go 编程语言

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

  •  
  •   eber · 237 天前 · 3056 次点击
    这是一个创建于 237 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    @2Nfree 好的,抽空我试试。
    danhahaha
        27
    danhahaha  
       236 天前
    连续俩帖子把我震住了,态度如此诚恳,此子必成大器
    danbai
        28
    danbai  
       236 天前 via Android
    哥们都用 golang 了你可以用用 rod 这个库
    eber
        29
    eber  
    OP
       235 天前
    @danbai 兄弟我来还愿了。经过这两天的体验,rod 库确实用起来比 chromedp 方便多了!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2626 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 03:21 · PVG 11:21 · LAX 19:21 · JFK 22:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.