使用 crypto/ssh 的 golang scp 文件
golang scp file using crypto/ssh
我正在尝试通过 ssh 下载远程文件
以下方法适用于 shell
ssh hostname "tar cz /opt/local/folder" > folder.tar.gz
然而,在 golang 上使用相同的方法会在输出工件大小上产生一些差异。例如,具有纯 shell 的相同文件夹会生成工件 gz 文件 179B,与 go 脚本 178B 相同。
我假设 io.Reader 中遗漏了某些内容或会话较早关闭。请大家帮忙。
这是我的脚本示例:
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
}
谢谢!
您可以尝试这样做:
r, _ := session.StdoutPipe()
reader := bufio.NewReader(r)
go func() {
defer session.Close()
// open file etc
// 10 is the number of bytes you'd like to copy in one write operation
p := make([]byte, 10)
for {
n, err := reader.Read(p)
if err == io.EOF {
break
}
if err != nil {
log.Fatal("err", err)
}
if _, err = file.Write(p[:n]); err != nil {
log.Fatal(err)
}
}
}()
确保您的 goroutine 已正确同步,以便将输出完整写入文件。
bufio.Scanner
用于换行符分隔的文本。根据文档,扫描器将删除换行符,从二进制文件中删除任何 10
s。
您不需要 goroutine 来执行复制,因为您可以使用 session.Start
异步启动该过程。
您可能也不需要使用 bufio。您应该使用 io.Copy 来复制文件,该文件在 ssh 客户端本身已经完成的任何缓冲之上已经有一个内部缓冲区。如果性能需要额外的缓冲区,请将会话输出包装在 bufio.Reader
中
最后,你 return 一个错误值,所以使用它而不是在常规错误情况下恐慌。
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
我正在尝试通过 ssh 下载远程文件 以下方法适用于 shell
ssh hostname "tar cz /opt/local/folder" > folder.tar.gz
然而,在 golang 上使用相同的方法会在输出工件大小上产生一些差异。例如,具有纯 shell 的相同文件夹会生成工件 gz 文件 179B,与 go 脚本 178B 相同。 我假设 io.Reader 中遗漏了某些内容或会话较早关闭。请大家帮忙。
这是我的脚本示例:
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
}
谢谢!
您可以尝试这样做:
r, _ := session.StdoutPipe()
reader := bufio.NewReader(r)
go func() {
defer session.Close()
// open file etc
// 10 is the number of bytes you'd like to copy in one write operation
p := make([]byte, 10)
for {
n, err := reader.Read(p)
if err == io.EOF {
break
}
if err != nil {
log.Fatal("err", err)
}
if _, err = file.Write(p[:n]); err != nil {
log.Fatal(err)
}
}
}()
确保您的 goroutine 已正确同步,以便将输出完整写入文件。
bufio.Scanner
用于换行符分隔的文本。根据文档,扫描器将删除换行符,从二进制文件中删除任何 10
s。
您不需要 goroutine 来执行复制,因为您可以使用 session.Start
异步启动该过程。
您可能也不需要使用 bufio。您应该使用 io.Copy 来复制文件,该文件在 ssh 客户端本身已经完成的任何缓冲之上已经有一个内部缓冲区。如果性能需要额外的缓冲区,请将会话输出包装在 bufio.Reader
最后,你 return 一个错误值,所以使用它而不是在常规错误情况下恐慌。
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