【go从零单排】Spawning Processes 、Exec‘ing Processes
🌈Don’t worry , just coding!
内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。
📗概念
在Go语言中,os/exec 和 syscall 包是用于执行外部命令和系统调用的两个重要包。
💻代码
Spawning Processes
package mainimport (//fmt:用于格式化输入输出。//io:用于处理输入输出操作。//os/exec:提供执行外部命令的功能。"fmt""io""os/exec"
)func main() {//创建一个命令对象 dateCmd,用于执行 date 命令。dateCmd := exec.Command("date")//调用 Output() 方法执行命令并获取输出。如果出错,则调用 panic(err) 终止程序。dateOut, err := dateCmd.Output()if err != nil {panic(err)}//打印命令的输出,即当前日期和时间。fmt.Println("> date")fmt.Println(string(dateOut))//尝试执行 date -x 命令(无效命令)。如果出现错误,使用类型断言处理不同类型的错误:_, err = exec.Command("date", "-x").Output()if err != nil {switch e := err.(type) {//如果是 *exec.Error,表示执行失败。case *exec.Error:fmt.Println("failed executing:", err)case *exec.ExitError: //如果是 *exec.ExitError,表示命令以非零状态码退出,可以获取退出代码。fmt.Println("command exit rc =", e.ExitCode())default://其他错误则调用 panic(err)。panic(err)}}//创建一个 grep 命令对象,用于查找包含 "hello" 的行。grepCmd := exec.Command("grep", "hello")//获取 grep 命令的标准输入和输出管道,启动命令。grepIn, _ := grepCmd.StdinPipe()grepOut, _ := grepCmd.StdoutPipe()grepCmd.Start()//向 grep 命令的标准输入写入两行文本,并关闭输入管道。grepIn.Write([]byte("hello grep\ngoodbye grep"))grepIn.Close()//从 grep 命令的标准输出读取所有字节,并等待命令完成。grepBytes, _ := io.ReadAll(grepOut)grepCmd.Wait()//打印 grep 命令的输出,应该只包含 "hello grep" 行。fmt.Println("> grep hello")fmt.Println(string(grepBytes))//创建一个 ls 命令对象,通过 bash -c 执行,使用 -a、-l 和 -h 选项列出当前目录的详细信息。lsCmd := exec.Command("bash", "-c", "ls -a -l -h")//调用 Output() 方法执行命令并获取输出。如果出错,则调用 panic(err)。lsOut, err := lsCmd.Output()if err != nil {panic(err)}fmt.Println("> ls -a -l -h")fmt.Println(string(lsOut))
}
Exec’ing Processes
package mainimport (//os:提供操作系统功能的接口。//os/exec:用于执行外部命令。//syscall:用于低级系统调用,包括执行程序。"os""os/exec""syscall"
)func main() {//使用 exec.LookPath 查找 ls 命令的完整路径。如果找不到命令,lookErr 将包含错误信息,并调用 panic(lookErr) 终止程序。binary, lookErr := exec.LookPath("ls")if lookErr != nil {panic(lookErr)}//创建一个字符串切片 args,包含要执行的命令及其参数://ls:命令名称。//-a:显示所有文件,包括隐藏文件。//-l:以详细列表格式显示。//-h:以人类可读的格式显示文件大小。args := []string{"ls", "-a", "-l", "-h"}//使用 os.Environ() 获取当前进程的环境变量,并将其存储在 env 中。env := os.Environ()//使用 syscall.Exec 执行查找到的命令 binary,并传递命令参数 args 和环境变量 env。//如果执行失败,execErr 将包含错误信息,并调用 panic(execErr) 终止程序。execErr := syscall.Exec(binary, args, env)if execErr != nil {panic(execErr)}
}
🔍理解
os/exec
os/exec 包提允许你创建、运行和控制外部进程。可以捕获输出、传递输入以及设置环境变量等。
package mainimport ("fmt""os/exec"
)func main() {cmd := exec.Command("ls", "-l") // 创建一个命令output, err := cmd.CombinedOutput() // 执行命令并获取输出if err != nil {fmt.Println("Error:", err)return}fmt.Println(string(output)) // 打印输出
}
syscall
syscall 包提供了对底层操作系统调用的访问,可以实现更复杂的功能,但通常需要更多的细节处理。
package mainimport ("fmt""syscall"
)func main() {pid, err := syscall.ForkExec("/bin/ls", []string{"ls", "-l"}, &syscall.ProcAttr{})if err != nil {fmt.Println("Error:", err)return}fmt.Println("Process ID:", pid) // 打印进程ID
}
💡 Tips
- os/exec:适合大多数场景,提供了简单易用的接口,适合执行和管理外部命令。
- syscall:适合需要底层操作系统交互的场景,功能更强大,但使用起来更复杂。
💪无人扶我青云志,我自踏雪至山巅。