# syscall.Exec的用法 ## 描述 经常在shell脚本里(特别是docker的启动脚本),经常会看到这么一条shell命令`exec $@`,这句话有什么意义? - $@ ,输出的是除脚本本身之后,后面携带的位置参数(这里携带的参数可以是另一个脚本的完全路径加所需参数) - exec 会执行参数指定的命令,但是并不会创建新的进程,只在当前进程空间内执行,即替换当前进程的执行内容,他们重用同一个进程号PID ## syscall.Exec 在go语言当中,要实现同样功能的话,可以使用syscall.Exec ``` package main import "time" import "syscall" import "os" import "os/exec" func main() { binary, err := exec.LookPath("sleep") if err != nil { panic(err) } args := []string{"sleep", "10"} env := os.Environ() time.Sleep(10 * time.Second) if err := syscall.Exec(binary, args, env); err != nil { panic(err) } } ``` syscall.Exec 需要三个参数: - 第一个参数是可执行文件的路径,注意不会自动从PATH下面去搜索,所以: - 要么是显式的指定全路径:/path/to/executable - 要么是显式的指定相对路径: ./relpath/to/executable - 要么通过exec.LookPath从PATH里面搜索出来,如本例子。 - 第二个参数是参数列表 - 注意args[0]是可执行程序名,这个内容会显示在ps -ef的输出中。用户可以改这个值,例如明明执行的是/usr/bin/sleep的可执行程序,但是这里可以改成任意字符串,例如ls,这样用户在ps -ef查看到的就是ls的命令在运行,而不是sleep命令,混淆用户。 - 后面是正常的参数。 - 第三个参数是环境变量 - 如果没有传,那么不会自动继承caller的环境变量的。 所以syscall.Exec只能是main函数的最后一条指令,它后面的代码不会被执行到。