资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

go语言重定向 go语言类型转换

如何使用Go语言实现远程执行命令

一般命令

创新互联专注于企业营销型网站建设、网站重做改版、坡头网站定制设计、自适应品牌网站建设、H5网站设计商城网站建设、集团公司官网建设、外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为坡头等各大城市提供网站开发制作服务。

所谓一般命令,就是在一定时间内会执行完的命令。比如 grep, cat 等等。 执行命令的步骤是:连接,执行,获取结果

连接

连接包含了认证,可以使用 password 或者 sshkey 2种方式来认证。下面的示例为了简单,使用了密码认证的方式来完成连接。

import (

"fmt"

"time"

"golang.org/x/crypto/ssh"

)

func connect(user, password, host string, port int) (*ssh.Session, error) {

var (

auth []ssh.AuthMethod

addr string

clientConfig *ssh.ClientConfig

client *ssh.Client

session *ssh.Session

err error

)

// get auth method

auth = make([]ssh.AuthMethod, 0)

auth = append(auth, ssh.Password(password))

clientConfig = ssh.ClientConfig{

User: user,

Auth: auth,

Timeout: 30 * time.Second,

}

// connet to ssh

addr = fmt.Sprintf("%s:%d", host, port)

if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {

return nil, err

}

// create session

if session, err = client.NewSession(); err != nil {

return nil, err

}

return session, nil

}

连接的方法很简单,只要提供登录主机的 用户*, *密码*, *主机名或者IP*, *SSH端口

执行,命令获取结果

连接成功后,执行命令很简单

import (

"fmt"

"log"

"os"

"time"

"golang.org/x/crypto/ssh"

)

func main() {

session, err := connect("root", "xxxxx", "127.0.0.1", 22)

if err != nil {

log.Fatal(err)

}

defer session.Close()

session.Run("ls /; ls /abc")

}

上面代码运行之后,虽然命令正常执行了,但是没有正常输出的结果,也没有异常输出的结果。 要想显示结果,需要将 session 的 Stdout 和 Stderr 重定向 修改 func main 为如下:

func main() {

session, err := connect("root", "xxxxx", "127.0.0.1", 22)

if err != nil {

log.Fatal(err)

}

defer session.Close()

session.Stdout = os.Stdout

session.Stderr = os.Stderr

session.Run("ls /; ls /abc")

}

这样就能在屏幕上显示正常,异常的信息了。

交互式命令

上面的方式无法远程执行交互式命令,比如 top , 远程编辑一个文件,比如 vi /etc/nginx/nginx.conf 如果要支持交互式的命令,需要当前的terminal来接管远程的 PTY。

func main() {

session, err := connect("root", "olordjesus", "dockers.iotalabs.io", 2210)

if err != nil {

log.Fatal(err)

}

defer session.Close()

fd := int(os.Stdin.Fd())

oldState, err := terminal.MakeRaw(fd)

if err != nil {

panic(err)

}

defer terminal.Restore(fd, oldState)

// excute command

session.Stdout = os.Stdout

session.Stderr = os.Stderr

session.Stdin = os.Stdin

termWidth, termHeight, err := terminal.GetSize(fd)

if err != nil {

panic(err)

}

// Set up terminal modes

modes := ssh.TerminalModes{

ssh.ECHO: 1, // enable echoing

ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud

ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud

}

// Request pseudo terminal

if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {

log.Fatal(err)

}

session.Run("top")

}

golang 控制重定向

在Client的字段中,有一个 CheckRedirect ,此字段就是用来控制重定向的函数,如果没有定义此字段的话,将会使用默认的 defaultCheckRedirect 方法。

默认的转发策略是最多转发10次。

在转发的过程中,某一些包含安全信息的Header,比如 Authorization 、 WWW-Authenticate 、 Cookie 等,如果转发是跨域的,那么这些Header不会复制到新的请求中。

http的重定向判断会默认处理以下状态码的请求:

301 (Moved Permanently)

302 (Found)

303 (See Other)

307 (Temporary Redirect)

308 (Permanent Redirect)

301、302和303请求将会改用Get访问新的请求,而307和308会使用原有的请求方式。

那么,我们如何去控制重定向的次数,甚至是禁止重定向呢?这里其实就需要我们自己去实现一个CheckRedirect函数了,首先我们来看看默认的defaultCheckRedirect方法:

第一个参数req是即将转发的request,第二个参数 via是已经请求过的requests。可以看到其中的逻辑是判断请求过的request数量,大于等于10的时候返回一个error,这也说明默认的最大重定向次数为10次,当此函数返回error时,即是重定向结束的时候。

所以如果需要设置重定向次数,那么复制一份这个函数,修改函数名字和其中if判断的数字,然后在生成Client时设定到Client即可:

或者:

禁止重定向则可以把判断数字修改为0。最好相应地修改errors中提示的信息。

如何让命令行程序支持管道和重定向输入

管道和重定向输入的数据都是通过标准输入传入程序的, os.Stdin 即为标准输入。

可以通过 golang.org/x/crypto/ssh/terminal 的 terminal.IsTerminal(0) 判断是否是管道和重定向输入,为什么是 0 :因为标准输入的文件描述符是 0

为 true 时表示是交互式环境

为 false 时是我们要的场景

首先需要安装 golang.org/x/crypto/ssh/terminal 这个包(安装时需要 VPN 的辅助):

go get golang.org/x/crypto/ssh/terminal

也可以使用 github.com/mattn/go-isatty 这个包:

!isatty.IsTerminal(os.Stdin.Fd())

下面是示例代码:

package mainimport (

"flag"

"fmt"

"io/ioutil"

"os"

"strings"

"golang.org/x/crypto/ssh/terminal")func main() {

flag.Parse()

data := flag.Args()

if !terminal.IsTerminal(0) {

     b, err := ioutil.ReadAll(os.Stdin)

     if err == nil {

             data = append(data, string(b))

     }

}

fmt.Println(strings.Join(data, " "))}

测试效果:

$ echo "hello" hello.txt

$ go run main.go hello world       # 参数输入hello world

$ cat hello.txt | go run main.go   # 管道输入hello

$ go run main.go hello.txt       # 重定向输入hello

$


当前文章:go语言重定向 go语言类型转换
文章链接:http://www.cdkjz.cn/article/dosjssj.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220