go语言重定向输入 go 重定向

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

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

创新互联建站主要从事做网站、成都做网站、网页设计、企业做网站、公司建网站等业务。立足成都服务阜阳,10余年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:028-86922220

可以通过 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

$

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中提示的信息。

golang 进程创建,fork,以及热重启(无缝升级)

一般来说,进程的操作使用的是一些系统的命令,所以go内部使用os包,进行一些运行系统命令的操作

os 包及其子包 os/exec 提供了创建进程的方法。

一般的,应该优先使用 os/exec 包。因为 os/exec 包依赖 os 包中关键创建进程的 API,为了便于理解,我们先探讨 os 包中和进程相关的部分。

Unix :fork创建一个进程,(及其一些变种,如 vfork、clone)。

Go:Linux 下创建进程使用的系统调用是 clone。

允许一进程(父进程)创建一新进程(子进程)。具体做法是,新的子进程几近于对父进程的翻版:子进程获得父进程的栈、数据段、堆和执行文本段的拷贝。可将此视为把父进程一分为二。

终止一进程,将进程占用的所有资源(内存、文件描述符等)归还内核,交其进行再次分配。参数 status 为一整型变量,表示进程的退出状态。父进程可使用系统调用 wait() 来获取该状态。

目的有二:其一,如果子进程尚未调用 exit() 终止,那么 wait 会挂起父进程直至子进程终止;其二,子进程的终止状态通过 wait 的 status 参数返回。

加载一个新程序(路径名为 pathname,参数列表为 argv,环境变量列表为 envp)到当前进程的内存。这将丢弃现存的程序文本段,并为新程序重新创建栈、数据段以及堆。通常将这一动作称为执行一个新程序。

没有直接提供 fork 系统调用的封装,而是将 fork 和 execve 合二为一,提供了 syscall.ForkExec。如果想只调用 fork,得自己通过 syscall.Syscall(syscall.SYS_FORK, 0, 0, 0) 实现。

os.Process 存储了通过 StartProcess 创建的进程的相关信息。

一般通过 StartProcess 创建 Process 的实例,函数声明如下:

它使用提供的程序名、命令行参数、属性开始一个新进程。StartProcess 是一个低级别的接口。os/exec 包提供了高级别的接口,一般应该尽量使用 os/exec 包。如果出错,错误的类型会是 *PathError。

属性定义如下:

FindProcess 可以通过 pid 查找一个运行中的进程。该函数返回的 Process 对象可以用于获取关于底层操作系统进程的信息。在 Unix 系统中,此函数总是成功,即使 pid 对应的进程不存在。

Process 提供了四个方法:Kill、Signal、Wait 和 Release。其中 Kill 和 Signal 跟信号相关,而 Kill 实际上就是调用 Signal,发送了 SIGKILL 信号,强制进程退出,关于信号,后续章节会专门讲解。

Release 方法用于释放 Process 对象相关的资源,以便将来可以被再使用。该方法只有在确定没有调用 Wait 时才需要调用。Unix 中,该方法的内部实现只是将 Process 的 pid 置为 -1。

通过 os 包可以做到运行外部命令,如前面的例子。不过,Go 标准库为我们封装了更好用的包: os/exec,运行外部命令,应该优先使用它,它包装了 os.StartProcess 函数以便更容易的重定向标准输入和输出,使用管道连接 I/O,以及作其它的一些调整。

exec.LookPath 函数在 PATH 指定目录中搜索可执行程序,如 file 中有 /,则只在当前目录搜索。该函数返回完整路径或相对于当前路径的一个相对路径。

func LookPath(file string) (string, error)

如果在 PATH 中没有找到可执行文件,则返回 exec.ErrNotFound。

Cmd 结构代表一个正在准备或者在执行中的外部命令,调用了 Run、Output 或 CombinedOutput 后,Cmd 实例不能被重用。

一般的,应该通过 exec.Command 函数产生 Cmd 实例:

用法

得到 * Cmd 实例后,接下来一般有两种写法:

前面讲到,通过 Cmd 实例后,有两种方式运行命令。有时候,我们不只是简单的运行命令,还希望能控制命令的输入和输出。通过上面的 API 介绍,控制输入输出有几种方法:

参考资料:


当前题目:go语言重定向输入 go 重定向
文章链接:http://myzitong.com/article/dojosid.html