
本文详解如何使用 Go 的 os/exec 包执行包含文件输入重定向(如本文详解如何使用 go 的 `os/exec` 包执行包含文件输入重定向(如 `
在 Go 中调用外部命令时,
exec.Command默认不经过 shell 解析,因此像、<code>>、|等 shell 特有操作符会被视为普通字符串参数,而非重定向指令。例如,以下写法是错误的:// ❌ 错误:bash 不会解析 '< text.txt',而是将 '<' 和 'text.txt' 当作 script.sh 的两个额外参数 exec.Command("/bin/bash", "script.sh", "<", "text.txt")正确做法是让
/bin/bash以-c模式运行——即显式启用 shell 解释器,使其能识别并处理重定向语法:package main import ( "fmt" "log" "os/exec" ) func main() { // ✅ 正确:通过 -c 让 bash 解析整个命令字符串 cmd := exec.Command("/bin/bash", "-c", "script.sh < text.txt") out, err := cmd.Output() if err != nil { log.Fatalf("command failed: %v, output: %s", err, string(out)) } fmt.Println(string(out)) }若需向脚本传递额外参数(如
arg1,arg2),可利用 bash-c的参数占位机制($1,$2, ...),避免字符串拼接带来的注入风险:cmd := exec.Command("/bin/bash", "-c", "script.sh \"$1\" \"$2\" < text.txt", "dummy", "arg1", "arg2") // 注意:第3个及之后的参数("dummy", "arg1", "arg2")依次赋给 $0, $1, $2 // 其中 "$0" 是命令名占位符(此处用 "dummy" 占位,实际未使用),"$1" 和 "$2" 对应真实参数更健壮的写法(推荐)——显式指定参数并确保路径安全:
cmd := exec.Command("/bin/bash", "-c", `./script.sh "$1" "$2" < "$3"`, "sh", "arg1", "arg2", "text.txt") // "$0"="sh", "$1"..."$3" 为传入参数⚠️ 重要注意事项:
- 永远避免字符串拼接用户输入:若
text.txt或参数来自不可信源,必须校验路径合法性(如使用filepath.Clean、限制目录范围),防止命令注入或路径遍历。- 检查脚本可执行权限:确保
script.sh具有+x权限,或显式调用bash script.sh。- 错误处理要完整:
cmd.Output()仅捕获 stdout;如需 stderr 或退出码,改用cmd.CombinedOutput()或cmd.Run()+cmd.ProcessState.ExitCode()。- 替代方案考虑:若仅需读取文件内容传入命令,可直接在 Go 中打开文件并设置
cmd.Stdin,绕过 shell 重定向(更安全、可控):file, err := os.Open("text.txt") if err != nil { log.Fatal(err) } defer file.Close() cmd := exec.Command("/bin/bash", "script.sh", "arg1", "arg2") cmd.Stdin = file out, err := cmd.Output()综上,Go 执行带重定向的 shell 命令的核心在于:委托 bash
-c解析命令字符串,而非依赖exec.Command的参数列表。合理使用参数占位与输入流绑定,可在功能、安全与可维护性之间取得最佳平衡。

















