首页 > 其他分享 >(转)go语言执行系统命令 - 标准库os/exec详解

(转)go语言执行系统命令 - 标准库os/exec详解

时间:2023-03-15 11:22:18浏览次数:36  
标签:Cmd err exec cmd go main os

原文:https://blog.csdn.net/weixin_49393427/article/details/116693536

exec包
对os.StartProcess的包装,方便重新映射标准输入输出,连接io到管道等。
exec包不调用系统shell,并且不支持shell通配符,或其他的扩展,管道,重定向等。如果需要这些功能,直接调用shell就可以,注意避免危险的输入,或者使用path/filepath包中的glob函数。如果需要扩展环境变量,使用os包的ExpandEnv
以下示例都是用Unix系统,可能无法在windows上运行。

func LookPath
func LookPath(file string) (string, error)
在环境变量搜索可执行文件,如果文件包含斜杠则直接尝试,不搜索。结果可能是绝对路径或相对于当前目录的相对路径。

package main

import (
"fmt"
"log"
"os/exec"
)

func main() {
path, err := exec.LookPath("ls")
if err != nil {
log.Fatal("ls not found")
}
fmt.Printf("ls is available at %s\n", path)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
结果:ls is available at /bin/ls

type cmd
type Cmd struct {
// 要运行的命令路径,如/bin/ls
Path string
// 命令参数
Args []string
// 环境变量,键值对形式
// 如果键重复,则最后一个生效
// 如果没有设置Env,则使用当前进程的环境变量
Env []string
// 指定工作目录,如果为空则为当前目录
Dir string
// 指定标准输入
// 如果为空则从os.DevNull读取
// 如果是*os.File,则读取该文件
// 默认情况,会有一个单独的goroutine从标准输入读取数据并通过管道传递给cmd。
// Wait不会停止,知道goroutine停止复制,到达标准输入结束(EOF或读取错误)
Stdin io.Reader
// 指定标准输出和标准输入
// 如果为空,Run的时候连接到os.DevNull
// 如果是*os.File,则连接到该文件
Stdout io.Writer
Stderr io.Writer
// ExtraFiles specifies additional open files to be inherited by the
// new process. It does not include standard input, standard output, or
// standard error. If non-nil, entry i becomes file descriptor 3+i.
// Windows不支持
ExtraFiles []*os.File
// 可选的特定于操作系统的属性SysProcAttr holds optional, operating system-specific attributes.
// Run把它作为os.ProcAttr的Sys字段传递给os.StartProcess
SysProcAttr *syscall.SysProcAttr
// 进程启动后的*os.Process对象
Process *os.Process
// 包含已退出的进程信息,可在调用Wait或者Run后获得
ProcessState *os.ProcessState
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
创建
func Command
func Command(name string, arg ...string) *Cmd
仅设置cmd的path和args
如果name不包含路径分隔符,则调用LookPath查找完整路径
arg不应包含命令本身
设置命令执行时的环境变量

package main

import (
"bytes"
"fmt"
"log"
"os"
"os/exec"
)

func main() {
cmd := exec.Command("ls", "-l")
var out bytes.Buffer
cmd.Stdout = &out
cmd.Env = append(os.Environ(),
"FOO=duplicate_value", // 重复被忽略
"FOO=actual_value", // 实际被使用
)
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Out: %q\n", out.String())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func CommandContext
func CommandContext(ctx context.Context, name string, arg ...string) *Cmd
包含上下文的*Cmd,如果上下文在命令完成之前完成,则提供的上下文通过os.Process.Kill终止进程
常用于为命令设置超时

package main

import (
"context"
"fmt"
"os/exec"
"time"
)

func main() {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
cmd := exec.CommandContext(ctx, "sleep", "5")

if err := cmd.Run(); err != nil {
fmt.Println(cmd.ProcessState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
执行结果:signal: killed

方法
func (*Cmd) CombinedOutput
func (c *Cmd) CombinedOutput() ([]byte, error)
运行命令并返回组合到一起的标准输出和标准错误

package main

import (
"fmt"
"log"
"os/exec"
)

func main() {
cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")
stdoutStderr, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", stdoutStderr)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
执行结果:stdout stderr
命令解释:echo stdout;输出stdout到标准输出;1>&2重定向标准输出到标准错误;输出stderr到标准错误

func (*Cmd) Output
func (c *Cmd) Output() ([]byte, error)
运行命令并返回标准输出

package main

import (
"fmt"
"log"
"os/exec"
)

func main() {
out, err := exec.Command("date").Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("The date is %s\n", out)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
命令运行成功,err为空;
命令运行失败,返回退出码为1
上述命令修改为exec.Command("date", "-h").Output(),则返回exit status 1

func (*Cmd) Run
func (c *Cmd) Run() error
运行命令,并等待,返回是否成功

package main

import (
"log"
"os/exec"
)

func main() {
cmd := exec.Command("sleep", "1")
log.Printf("Running command and waiting for it to finish...")
err := cmd.Run()
log.Printf("Command finished with error: %v", err)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
func (*Cmd) Start
func (c *Cmd) Start() error
启动执行命令,但不等待,如果启动成功返回,会设置c.Process字段
一旦命令接触,Wait方法将返回退出代码并释放资源,也就是通过Wait来等待进程结束

package main

import (
"log"
"os/exec"
)

func main() {
cmd := exec.Command("sleep", "5")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...")
err = cmd.Wait()
log.Printf("Command finished with error: %v", err)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func (*Cmd) StderrPipe
获得标准输入输出错误的管道

func (*Cmd) String
func (c *Cmd) String() string
返回人类可读的C描述,仅用于输出,不适合作为shell输入

func (*Cmd) Wait
func (c *Cmd) Wait() error
等待命令退出,等待所有标准输入输出错误复制完成,必须通过start启动

示例
读取输出,一次性/缓冲区按行
stdout, err := cmd.StdoutPipe()
//读取所有输出
bytes, err := ioutil.ReadAll(stdout)
if err != nil {
fmt.Println("ReadAll Stdout:", err.Error())
return
}
//使用带缓冲的读取器
outputBuf := bufio.NewReader(stdout)
for {
//一次获取一行,_ 获取当前行是否被读完
output, _, err := outputBuf.ReadLine()
if err != nil {
// 判断是否到文件的结尾了否则出错
if err.Error() != "EOF" {
fmt.Printf("Error :%s\n", err)
}
return
}
fmt.Printf("%s\n", string(output))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
简单的交互shell
package main

import (
"bufio"
"fmt"
"os"
"os/exec"
"strings"
)

func main() {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("> ")
// Read the keyboad input.
input, err := reader.ReadString('\n')
if err != nil {
fmt.Fprintln(os.Stderr, err)
}

// Handle the execution of the input.
if err = execInput(input); err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
}

func execInput(input string) error {
// Remove the newline character.
input = strings.TrimSuffix(input, "\n")

// Prepare the command to execute.
cmd := exec.Command(input)

// Set the correct output device.
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout

// Execute the command and return the error.
return cmd.Run()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
命令组合,管道连接命令输入输出
package main

import (
"os"
"os/exec"
)

func main() {
c1 := exec.Command("grep", "Accepted", "/var/log/auth.log")
c2 := exec.Command("wc", "-l")
c2.Stdin, _ = c1.StdoutPipe()
c2.Stdout = os.Stdout
_ = c2.Start()
_ = c1.Run()
_ = c2.Wait()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
参考
Golang 调用 Linux 命令
Package exec
Golang - Execute command
[译] 使用 Go 语言编写一个简单的 SHELL
————————————————

标签:Cmd,err,exec,cmd,go,main,os
From: https://www.cnblogs.com/liujiacai/p/17217845.html

相关文章

  • VS CODE运行DJango项目中遇到:{无法加载文件 D:\code\python_project\virtualenv\e
    如题在vscode中在切换python解释器(输入之前创建的虚拟环境的解释器路径)后,打开控制板会报一下错误:无法加载文件D:\code\python_project\virtualenv\env-py3.8.2\Scripts......
  • mongodb日常管理
     db.serverStatus()##查看系统状态db.currentOp()##查看正在运行的会话db.killOp()##获取到opid,杀掉会话db.getProfilingLevel()##获取日志级别 ......
  • Mongodb创建用户角色
    一、Mongodb数据库用户角色?MongoDB采用基于角色的访问控制(RBAC)来确定用户的访问。授予用户一个或多个角色,确定用户对MongoDB资源的访问权限和用户可以执行哪些操作。......
  • gin跨域(CROS)时GET和POST正常但PUT和DELETE被阻止
    问题表现同一个项目请求同一个服务时,Get和Post请求正常,但是Put和Delete一直报跨域错误的问题AccesstoXMLHttpRequestat'http://127.0.0.1:8011/api/organization'fr......
  • PHP message: PHP Fatal error: Uncaught Error: Class 'Mongo' not found
    brew+Nginx+PHP7+MongoDB3.2.9+Mongo-PHP_driver1.40搭好环境后写了个脚本:<?php$connection=newMongo();?>通过网页访问,网页显示空白,查看nginx的错......
  • golang的命令行参数os.Args和flag
    os.Args是一个string的切片,用来存储所有的命令行参数1.基本使用packagemainimport("fmt""os")funcmain(){fmt.Println("命令行的参数有",len(......
  • postman调试grpc接口
    一直用postman调试http接口,很顺手。这次试了下调试grpc接口,方便  然后导入proto文件  选择调用的grpc接口,调用 ......
  • Centos8 设置开机自启动脚本
    在CentOS8之前通过把需要开机执行的命令写入到/etc/rc.local就解决了开机启动问题,但是从CentOS8开始写入到rc.local将无法自动启动,需要设置rc.local这个服务自启解决开......
  • python读取mongodb并写入文件
     #!/usr/bin/envpython#coding=utf-8frompymongoimportMongoClientimporttimefromdatetimeimportdatetimedefchaxun_data():##client=MongoCl......
  • Go内存管理逃逸分析
    1.前言所谓的逃逸分析(Escapeanalysis)是指由编译器决定内存分配的位置吗不需要程序员指定。函数中申请一个新的对象如果分配在栈中,则函数执行结束后可自动将内存回......