使用crypto/ssh的golang scp文件

nev*_*gny 4 ssh scp go

我正在尝试通过 ssh 下载远程文件以下方法在 shell 上工作正常

ssh hostname "tar cz /opt/local/folder" > folder.tar.gz
Run Code Online (Sandbox Code Playgroud)

然而,golang 上的相同方法在输出工件大小方面存在一些差异。例如,与纯 shell 相同的文件夹产生工件 gz 文件 179B,与 go script 178B 相同。我认为 io.Reader 中遗漏了一些东西,或者 session 更早关闭了。恳请各位大侠帮忙。

这是我的脚本示例:

func executeCmd(cmd, hostname string, config *ssh.ClientConfig, path string) error {
    conn, _ := ssh.Dial("tcp", hostname+":22", config)
    session, err := conn.NewSession()
    if err != nil {
        panic("Failed to create session: " + err.Error())
    }

    r, _ := session.StdoutPipe()
    scanner := bufio.NewScanner(r)

    go func() {
        defer session.Close()

        name := fmt.Sprintf("%s/backup_folder_%v.tar.gz", path, time.Now().Unix())
        file, err := os.OpenFile(name, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
        if err != nil {
            panic(err)
        }
        defer file.Close()
        for scanner.Scan() {
            fmt.Println(scanner.Bytes())
            if err := scanner.Err(); err != nil {
                fmt.Println(err)
            }

            if _, err = file.Write(scanner.Bytes()); err != nil {
                log.Fatal(err)

            }
        }
    }()

    if err := session.Run(cmd); err != nil {
        fmt.Println(err.Error())
        panic("Failed to run: " + err.Error())
    }

    return nil
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Jim*_*imB 5

bufio.Scanner用于换行分隔的文本。根据文档,扫描程序将删除换行符,10从二进制文件中删除任何s。

您不需要 goroutine 来进行复制,因为您可以使用它session.Start来异步启动进程。

您可能也不需要使用 bufio。您应该使用 io.Copy 来复制文件,该文件在 ssh 客户端本身已经完成的任何缓冲之上已经有一个内部缓冲区。如果需要额外的缓冲区来提高性能,请将会话输出包装在一个bufio.Reader

最后,您返回一个错误值,因此请使用它而不是在常规错误条件下恐慌。

conn, err := ssh.Dial("tcp", hostname+":22", config)
if err != nil {
    return err
}

session, err := conn.NewSession()
if err != nil {
    return err
}
defer session.Close()

r, err := session.StdoutPipe()
if err != nil {
    return err
}

name := fmt.Sprintf("%s/backup_folder_%v.tar.gz", path, time.Now().Unix())
file, err := os.OpenFile(name, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
    return err
}
defer file.Close()

if err := session.Start(cmd); err != nil {
    return err
}

n, err := io.Copy(file, r)
if err != nil {
    return err
}

if err := session.Wait(); err != nil {
    return err
}

return nil
Run Code Online (Sandbox Code Playgroud)